braille output
This commit is contained in:
parent
f452a6e869
commit
1d209d6ba1
1 changed files with 48 additions and 7 deletions
55
src/main.rs
55
src/main.rs
|
|
@ -1,6 +1,16 @@
|
||||||
use std::{env, error::Error};
|
use std::{
|
||||||
|
env,
|
||||||
|
error::Error,
|
||||||
|
io::{self, BufWriter, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use image::{DynamicImage, ImageReader, Luma};
|
use image::{ImageReader, Luma};
|
||||||
|
|
||||||
|
const BRAILLE_FIRST_BYTE: u8 = 0xe2;
|
||||||
|
const BRAILLE_SECOND_BYTE: u8 = 0xa0;
|
||||||
|
const BRAILLE_HEIGHT: u8 = 4;
|
||||||
|
const BRAILLE_BIT_MAPPING: [[u8; BRAILLE_HEIGHT as usize]; 2] =
|
||||||
|
[[0x1, 0x2, 0x4, 0x40], [0x8, 0x10, 0x20, 0x80]];
|
||||||
|
|
||||||
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
@ -12,16 +22,25 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
];
|
];
|
||||||
|
|
||||||
let src = env::args().nth(1).ok_or("i need a source path")?;
|
let src = env::args().nth(1).ok_or("i need a source path")?;
|
||||||
let out_path = env::args().nth(2).ok_or("i need an output path")?;
|
|
||||||
let mut img = ImageReader::open(&src)?.decode()?.to_luma32f();
|
let mut img = ImageReader::open(&src)?.decode()?.to_luma32f();
|
||||||
let mut out = img.clone();
|
|
||||||
|
let mut out = BufWriter::new(io::stdout().lock());
|
||||||
|
|
||||||
|
let mut output_line = vec![0u8; img.width().div_ceil(2) as usize];
|
||||||
|
let mut lines_buffered: u8 = 0;
|
||||||
|
|
||||||
for y in 0..img.height() {
|
for y in 0..img.height() {
|
||||||
for x in 0..img.width() {
|
for x in 0..img.width() {
|
||||||
let old_pixel = img.get_pixel(x, y);
|
let old_pixel = img.get_pixel(x, y);
|
||||||
let old_luma = old_pixel.0[0];
|
let old_luma = old_pixel.0[0];
|
||||||
let luma = if old_luma < 0.5 { 0. } else { 1. };
|
let white = old_luma > 0.5;
|
||||||
|
let luma = if white { 1. } else { 0. };
|
||||||
|
|
||||||
out.put_pixel(x, y, Luma([luma]));
|
// white pixels are filled because i'm targetting a dark mode site
|
||||||
|
if white {
|
||||||
|
output_line[(x / 2) as usize] |=
|
||||||
|
BRAILLE_BIT_MAPPING[(x % 2) as usize][(y % 4) as usize];
|
||||||
|
}
|
||||||
|
|
||||||
let error = old_luma - luma;
|
let error = old_luma - luma;
|
||||||
for (dx, dy, quant) in kernel {
|
for (dx, dy, quant) in kernel {
|
||||||
|
|
@ -39,7 +58,29 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
img.put_pixel(x, y, Luma([corrected]));
|
img.put_pixel(x, y, Luma([corrected]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lines_buffered += 1;
|
||||||
|
if lines_buffered == BRAILLE_HEIGHT {
|
||||||
|
for byte in &output_line {
|
||||||
|
if *byte == 0 {
|
||||||
|
out.write_all(b" ").unwrap();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let upper_2 = byte >> 6;
|
||||||
|
let lower_6 = byte & 0b111_111;
|
||||||
|
out.write_all(&[
|
||||||
|
BRAILLE_FIRST_BYTE,
|
||||||
|
BRAILLE_SECOND_BYTE | upper_2,
|
||||||
|
0b10_000000 | lower_6,
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
out.write_all(b"\n").unwrap();
|
||||||
|
|
||||||
|
output_line.fill(0);
|
||||||
|
lines_buffered = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DynamicImage::from(out).into_luma8().save(out_path)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue