use std::{env, fs, io, process::exit};
#[cfg(not(feature = "fontdue"))]
fn main () {
panic!("Rasterization requires feature fontdue")
}
#[cfg(feature = "fontdue")]
fn main() {
let mut args = env::args();
let myname = args.next().unwrap_or("insa".to_owned());
let myversion = env!["CARGO_PKG_VERSION"];
let mut options_done = false;
let mut font = None;
let usage = move |error| {
let output = format!(
"Insa rasterize {myversion}\nUsage: {myname} font <utf-8-brushes\n - it works well with unifont 15\n - use it to make a brush map for insa"
);
if let Some(error) = &error {
eprintln!("{error}\n\n{output}");
exit(1);
} else {
println!("{output}");
exit(0);
}
};
while let Some(arg) = args.next() {
match arg.as_str() {
"--help" => {
usage(None);
}
"--version" => {
println!("Insa {myversion}");
return;
}
"--" => options_done = true,
_ if !options_done && arg.starts_with("--") => {
usage(Some(format!("Unknown option {arg}")));
}
_ => {
if font.is_some() {
usage(Some(format!("Give us only one font")))
} else {
font = Some(arg)
}
}
}
}
let font = if let Some(font) = font {
font
} else {
usage(Some("Give Insa some font to play with".into()));
return;
};
let font = fs::read(font).expect("reading font data");
let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default())
.expect("loading font data");
let mut input = Chars::new(io::stdin());
while let Some(c) = input.next() {
match c {
Err(e) => panic!("Error reading brushes: {e:?}"),
Ok(c) => {
let bitmap = insa::rasterize_u128(&font, c);
eprint!(
"{}",
insa::dump_bitmap_u128(bitmap)
.replace("0b", "//")
.replace("0", " ")
.replace("1", "█")
.replace("\n", "|\n")
);
println!("(0b{bitmap:0128b},'{c}'),")
}
}
}
}
struct Chars<R> {
reader: R,
pos: usize,
char: [u8; 4],
}
impl<R> Chars<R> {
fn new(reader: R) -> Self {
Self {
reader,
pos: 0,
char: Default::default(),
}
}
}
impl<R: io::Read> Iterator for Chars<R> {
type Item = Result<char, io::Result<Vec<u8>>>;
fn next(&mut self) -> Option<Self::Item> {
let bytes = |me: &mut Self| {
let bs = me.char.iter().cloned().take(me.pos).collect();
me.pos = 0;
me.char.fill(0);
Some(Err(Ok(bs)))
};
loop {
break match self.reader.read(&mut self.char[self.pos..self.pos + 1]) {
Err(e) => Some(Err(Err(e))),
Ok(0) => {
if self.pos == 0 {
None
} else {
bytes(self)
}
}
Ok(_) => {
if let Ok(str) = std::str::from_utf8(&self.char[..self.pos + 1]) {
let c = str.chars().next().expect("first char");
self.char.fill(0);
self.pos = 0;
if c == '\n' {
continue;
} else {
Some(Ok(c))
}
} else if self.pos < 4 {
self.pos += 1;
continue;
} else {
bytes(self)
}
}
};
}
}
}