You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.7 KiB
132 lines
4.7 KiB
|
|
pub fn convert_bitmap_to_unicode(w: usize, h: usize, data: Vec<u8>) -> Vec<Vec<char>> |
|
{ |
|
|
|
const CHARS: [&str; 4] = [ |
|
" ⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿", |
|
"⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿", |
|
"⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿", |
|
"⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿", |
|
]; |
|
let bitchars = CHARS.iter().flat_map(|t| t.chars()).collect::<Vec<_>>(); |
|
|
|
let px = |i: usize, j: usize| if i < w && j < h {data[j * w + i]} else {0}; |
|
|
|
let mut output = vec![]; |
|
|
|
for j in (0..h).step_by(4) |
|
{ |
|
let mut line = vec![]; |
|
for i in (0..w).step_by(2) |
|
{ |
|
let mut index = 0; |
|
index |= if px(i+0, j+0) < 128 {0} else {1 << 0}; |
|
index |= if px(i+0, j+1) < 128 {0} else {1 << 1}; |
|
index |= if px(i+0, j+2) < 128 {0} else {1 << 2}; |
|
index |= if px(i+0, j+3) < 128 {0} else {1 << 3}; |
|
index |= if px(i+1, j+0) < 128 {0} else {1 << 4}; |
|
index |= if px(i+1, j+1) < 128 {0} else {1 << 5}; |
|
index |= if px(i+1, j+2) < 128 {0} else {1 << 6}; |
|
index |= if px(i+1, j+3) < 128 {0} else {1 << 7}; |
|
|
|
line.push(bitchars[index]); |
|
} |
|
output.push(line); |
|
} |
|
|
|
output |
|
} |
|
|
|
|
|
fn read_jpeg_to_bitmap(file: &str) -> (usize, usize, Vec<u8>) |
|
{ |
|
use zune_jpeg::zune_core::{colorspace::ColorSpace, options::DecoderOptions, bytestream::ZCursor}; |
|
let data = std::fs::read(file).unwrap(); |
|
let options = DecoderOptions::default().jpeg_set_out_colorspace(ColorSpace::Luma); |
|
let mut decoder = zune_jpeg::JpegDecoder::new_with_options(ZCursor::new(&data), options); |
|
let pixels = decoder.decode().unwrap(); |
|
let (w, h) = decoder.dimensions().unwrap(); |
|
(w, h, pixels) |
|
} |
|
|
|
|
|
fn main() |
|
{ |
|
match std::env::args().collect::<Vec<_>>().as_slice() { |
|
[_, bitmap_file, source_file, output_file] => |
|
{ |
|
let (w, h, pixels) = read_jpeg_to_bitmap(&bitmap_file); |
|
|
|
let char_bitmap = convert_bitmap_to_unicode(w, h, pixels); |
|
|
|
let source = std::fs::read_to_string(source_file).unwrap(); |
|
|
|
let max_width = 120; |
|
|
|
let mut modified_lines = vec![]; |
|
let mut buffer = Vec::with_capacity(1024); |
|
let mut row = 0; |
|
|
|
for line in source.lines() |
|
{ |
|
buffer.clear(); |
|
buffer.extend(line.chars()); |
|
if buffer.len() < max_width { |
|
let needed = max_width - buffer.len(); |
|
buffer.extend(core::iter::repeat(' ').take(needed)); |
|
} |
|
|
|
let mut i = 0; |
|
for j in 0..buffer.len() |
|
{ |
|
if !buffer[j].is_whitespace() |
|
{ |
|
if j - i > 3 |
|
{ |
|
let bmp_row = &char_bitmap[row]; |
|
for k in i..j { |
|
buffer[k] = bmp_row[k % bmp_row.len()]; |
|
} |
|
buffer[i ] = '/'; |
|
buffer[i+1] = '*'; |
|
buffer[j-1] = '/'; |
|
buffer[j-2] = '*'; |
|
} |
|
|
|
i = j + 1; |
|
} |
|
} |
|
|
|
let j = buffer.len(); |
|
if j - i > 3 |
|
{ |
|
let bmp_row = &char_bitmap[row]; |
|
for k in i..j { |
|
buffer[k] = bmp_row[k % bmp_row.len()]; |
|
} |
|
buffer[i ] = '/'; |
|
buffer[i+1] = '*'; |
|
buffer[j-1] = '/'; |
|
buffer[j-2] = '*'; |
|
} |
|
|
|
modified_lines.push(buffer.iter().collect::<String>()); |
|
row += 1; |
|
} |
|
|
|
let new_source = modified_lines.join("\n"); |
|
|
|
println!("{new_source}"); |
|
|
|
std::fs::write(output_file, new_source).unwrap(); |
|
} |
|
[path] => |
|
{ |
|
println!("usage: {path} art.jpg input_src output_src"); |
|
} |
|
_ => |
|
{ |
|
} |
|
} |
|
|
|
}
|
|
|