diff --git a/src/dithering.rs b/src/dithering.rs index 8006276..bc33b6f 100644 --- a/src/dithering.rs +++ b/src/dithering.rs @@ -1,44 +1,31 @@ -use image::DynamicImage; +use image::{ + DynamicImage, GrayImage, + imageops::{self, colorops}, +}; +pub fn auto_brighten(gray: &mut GrayImage) -> () { + let avg = gray.pixels().map(|p| p.0[0] as u32).sum::() / gray.len() as u32; + + if avg < 100 { + colorops::brighten_in_place(gray, 40); + colorops::contrast_in_place(gray, 25.0); + } else if avg > 180 { + colorops::brighten_in_place(gray, -15); + } +} + +pub fn dither(gray: &mut GrayImage) -> Vec { + imageops::dither(gray, &imageops::colorops::BiLevel); -pub fn atkinson_mono(img: &DynamicImage) -> Vec { - let mut gray = img.to_luma8(); let (w, h) = (gray.width() as usize, gray.height() as usize); let pitch = (w + 7) >> 3; let mut bits = vec![0u8; pitch * h]; - let buf = gray.as_mut(); for y in 0..h { - let row = y * w; for x in 0..w { - let i = row + x; - let old = buf[i]; - let new = if old < 128 { 0 } else { 255 }; - buf[i] = new; - let bit = new == 0; - if bit { - let byte = y * pitch + (x >> 3); - bits[byte] |= 128 >> (x & 7); - } - let err = ((old as i16) - (new as i16)) / 8; - - if x + 1 < w { - buf[i + 1] = (buf[i + 1] as i16 + err).clamp(0, 255) as u8; - } - if x + 2 < w { - buf[i + 2] = (buf[i + 2] as i16 + err).clamp(0, 255) as u8; - } - if y + 1 < h { - let down = i + w; - if x > 0 { - buf[down - 1] = (buf[down - 1] as i16 + err).clamp(0, 255) as u8; - } - buf[down] = (buf[down] as i16 + err).clamp(0, 255) as u8; - if x + 1 < w { - buf[down + 1] = (buf[down + 1] as i16 + err).clamp(0, 255) as u8; - } - if y + 2 < h { - buf[down + w] = (buf[down + w] as i16 + err).clamp(0, 255) as u8; - } + let byte = y * pitch + (x >> 3); + let bit = 7 - (x & 7); + if gray[(x as u32, y as u32)].0[0] == 0 { + bits[byte] |= 1 << bit; } } } diff --git a/src/escpos/job.rs b/src/escpos/job.rs index 7910ba4..ebd34ba 100644 --- a/src/escpos/job.rs +++ b/src/escpos/job.rs @@ -1,4 +1,7 @@ -use crate::{dithering::atkinson_mono, escpos::errors::EscPosError}; +use crate::{ + dithering::{auto_brighten, dither}, + escpos::errors::EscPosError, +}; use image::{DynamicImage, imageops::FilterType}; #[repr(u8)] @@ -26,7 +29,11 @@ pub enum ImageOrientation { Largest, } #[repr(u8)] -pub enum JustifyOrientation {} +pub enum JustifyOrientation { + Left = 0, + Center = 1, + Rigth = 2, +} #[repr(u8)] pub enum TextEffect { @@ -59,7 +66,7 @@ impl Job { let amount = amount.unwrap_or(1); self.content.extend_from_slice(&[0x1B, b'd', amount]) } - // pub fn write_text(&mut self, text: String, ) + pub fn write_text(&mut self, text: String) {} pub fn write_bitmap( &mut self, img: &DynamicImage, @@ -91,7 +98,10 @@ impl Job { DynamicImage::ImageRgba8(image::imageops::resize(img, w, h, FilterType::Triangle)); let img = if swap { img.rotate90() } else { img }; - let mono = atkinson_mono(&img); + let mut gray = img.to_luma8(); + auto_brighten(&mut gray); + + let mono = dither(&mut gray); let width_bytes = ((w + 7) >> 3) as u16; let buf = &mut self.content; diff --git a/src/main.rs b/src/main.rs index 1a5f710..91bef30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,36 +10,35 @@ use crate::escpos::{ }; fn main() { - // let args: Vec = env::args().collect(); - // - // let len = args.len(); - // if len < 2 || len > 2 { - // println!("Please provide a path to the image."); - // process::exit(1); - // } - // - // let img = ImageReader::open(&args[1]) - // .map_err(|err| ImageError::IoError(err)) - // .and_then(|v| v.decode()) - // .unwrap(); + let args: Vec = env::args().collect(); + + let len = args.len(); + if len < 2 || len > 2 { + println!("Please provide a path to the image."); + process::exit(1); + } + + let img = ImageReader::open(&args[1]) + .map_err(|err| ImageError::IoError(err)) + .and_then(|v| v.decode()) + .unwrap(); let mut printer = Printer::new(384); let job = printer.new_job().unwrap(); - job.write_qr("https://pornhub.com".to_string(), None, None) - // .unwrap(); - // job.write_barcode( - // "kleintje".to_string(), - // Some(10), - // None, - // Some(BARTextPosition::Both), - // Some(BARType::CODE128), - // ) - .unwrap(); - job.content.extend_from_slice(&[b'\n', b'\n']); - // job.write_bitmap(&img, None, None).unwrap(); + job.write_feed(Some(2)); + // job.write_barcode( + // "kleintje".to_string(), + // Some(10), + // None, + // Some(BARTextPosition::Both), + // Some(BARType::CODE128), + // ) + // .unwrap(); + job.write_bitmap(&img, None, None).unwrap(); + job.write_feed(Some(2)); job.ready = true; - println!("{}", printer.queue.len()); + // println!("{:?}", job.content); let mut out = std::fs::File::create("/dev/usb/lp0").unwrap(); printer.print_job(&mut out).unwrap();