use std::error::Error;
use std::path::Path;
use std::fs::File;
use std::fmt;
use std::fmt::Write;
use png::Decoder;
use colored::*;
pub struct Image {
data: Vec<u8>,
width: u32,
height: u32,
}
impl Image {
pub fn new(path: &Path) -> Result<Image, Box<dyn Error>> {
let decoder = Decoder::new(File::open(path)?);
let mut reader = decoder.read_info()?;
let mut img_data = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut img_data)?;
if info.color_type != png::ColorType::Rgba {
return Err("PNG is not of color_type Rgba".into());
}
Ok( Image { data: img_data,
width: info.width,
height: info.height, } )
}
pub fn as_string(&self) -> Result<String, Box<dyn Error>> {
let img = self;
let mut buf = String::new();
for y in (0..img.height).step_by(2) {
for x in (0..(img.width * 4)).step_by(4) {
let top = y * (img.width * 4) + x;
let t = top as usize;
let tr = img.data[t];
let tg = img.data[t+1];
let tb = img.data[t+2];
let (br, bg, bb);
if y+1 != img.height {
let bot = (y+1) * (img.width * 4) + x;
let b = bot as usize;
br = img.data[b];
bg = img.data[b+1];
bb = img.data[b+2];
} else {
(br, bg, bb) = (0, 0, 0)
}
write!(&mut buf, "{0}", "▀".truecolor(tr, tg, tb).on_truecolor(br, bg, bb))?;
}
writeln!(&mut buf)?;
}
Ok(buf)
}
}
impl fmt::Display for Image {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buf = self.as_string().map_err(|_| fmt::Error)?;
write!(f, "{}", buf)?;
Ok(())
}
}