From be3fd25fcfbf067bde4dba4fcddd2ed5a01abf06 Mon Sep 17 00:00:00 2001 From: Jurn Wubben Date: Thu, 25 Sep 2025 12:49:25 +0200 Subject: [PATCH] Progress on modularizing escpos. --- src/escpos/errors.rs | 7 +++ src/{escpos.rs => escpos/job.rs} | 77 +++++++------------------------- src/escpos/mod.rs | 3 ++ src/escpos/printer.rs | 49 ++++++++++++++++++++ src/main.rs | 51 +++++++++++---------- 5 files changed, 103 insertions(+), 84 deletions(-) create mode 100644 src/escpos/errors.rs rename src/{escpos.rs => escpos/job.rs} (71%) create mode 100644 src/escpos/mod.rs create mode 100644 src/escpos/printer.rs diff --git a/src/escpos/errors.rs b/src/escpos/errors.rs new file mode 100644 index 0000000..d40865f --- /dev/null +++ b/src/escpos/errors.rs @@ -0,0 +1,7 @@ +#[derive(Debug)] +pub enum EscPosError { + EmptyQueue, + InvalidQueueIndex, + InvalidBitmapMode, + InvalidBarcodeLength(String), +} diff --git a/src/escpos.rs b/src/escpos/job.rs similarity index 71% rename from src/escpos.rs rename to src/escpos/job.rs index 13d33f8..5a0a75f 100644 --- a/src/escpos.rs +++ b/src/escpos/job.rs @@ -1,16 +1,5 @@ -use crate::dithering::atkinson_mono; +use crate::{dithering::atkinson_mono, escpos::errors::EscPosError}; use image::{DynamicImage, imageops::FilterType}; -use std::{collections::HashMap, io::Write, ops::AddAssign}; - -const MAX_WIDTH: u32 = 384; - -#[derive(Debug)] -pub enum EscPosError { - EmptyQueue, - InvalidQueueIndex, - InvalidBitmapMode, - InvalidBarcodeLength(String), -} #[repr(u8)] pub enum QREcc { @@ -39,11 +28,9 @@ pub enum ImageOrientation { } pub struct Job { - content: Vec, pub ready: bool, -} -pub struct Printer { - pub queue: Vec, + pub content: Vec, + max_width: u16, } fn is_numeric(s: &[u8]) -> bool { @@ -51,10 +38,11 @@ fn is_numeric(s: &[u8]) -> bool { } impl Job { - pub fn new() -> Self { + pub fn new(max_width: u16) -> Self { Job { content: vec![0x1B, b'@'], ready: false, + max_width: max_width, } } @@ -71,18 +59,18 @@ impl Job { let (w, h) = (img.width(), img.height()); let swap = matches!(orientation, Some(ImageOrientation::Largest)) - && h.min(MAX_WIDTH) * w > w.min(MAX_WIDTH) * h; + && h.min(self.max_width as u32) * w > w.min(self.max_width as u32) * h; let scale = if swap { - MAX_WIDTH as f32 / h as f32 + self.max_width as f32 / h as f32 } else { - MAX_WIDTH as f32 / w as f32 + self.max_width as f32 / w as f32 }; let (w, h) = if swap { - ((h as f32 * scale) as u32, MAX_WIDTH) + ((h as f32 * scale) as u32, self.max_width as u32) } else { - (MAX_WIDTH, (h as f32 * scale) as u32) + (self.max_width as u32, (h as f32 * scale) as u32) }; let img = @@ -95,6 +83,8 @@ impl Job { let buf = &mut self.content; buf.reserve(8 + mono.len()); buf.extend_from_slice(&[ + 0x1B, + b'@', 0x1D, 0x76, 0x30, @@ -124,6 +114,8 @@ impl Job { let text = text.as_bytes(); let len = text.len() + 3; buf.extend_from_slice(&[ + 0x1B, + b'@', // Size 0x1D, 0x28, @@ -186,6 +178,8 @@ impl Job { let buf = &mut self.content; buf.extend([ + 0x1B, + b'@', 0x1D, 0x68, height, @@ -205,42 +199,3 @@ impl Job { Ok(()) } } -impl Printer { - pub fn new() -> Self { - Printer { queue: Vec::new() } - } - - pub fn new_job(&mut self) -> Result<&mut Job, EscPosError> { - self.queue.push(Job::new()); - self.queue.last_mut().ok_or(EscPosError::InvalidQueueIndex) - } - pub fn print_job(&mut self, writer: &mut impl Write) -> Result<(), EscPosError> { - let page_feed: u8 = 0x0A; - let job = self - .queue - .extract_if(.., |j| j.ready) - .next() - .ok_or(EscPosError::EmptyQueue)?; - - // writer.write(&[page_feed]).unwrap(); // FIXME: remove unwraps - writer.write(&job.content).unwrap(); - // writer.write(&[page_feed]).unwrap(); - - Ok(()) - } - pub fn export_job(&mut self) -> Result, EscPosError> { - let page_feed: u8 = 0x0A; - let job = self - .queue - .extract_if(.., |j| j.ready) - .next() - .ok_or(EscPosError::EmptyQueue)?; - - let mut out = Vec::with_capacity(2 + job.content.len()); - out.push(page_feed); - out.extend(job.content); - out.push(page_feed); - - Ok(out) - } -} diff --git a/src/escpos/mod.rs b/src/escpos/mod.rs new file mode 100644 index 0000000..b03aae7 --- /dev/null +++ b/src/escpos/mod.rs @@ -0,0 +1,3 @@ +pub mod errors; +pub mod job; +pub mod printer; diff --git a/src/escpos/printer.rs b/src/escpos/printer.rs new file mode 100644 index 0000000..42a0e3c --- /dev/null +++ b/src/escpos/printer.rs @@ -0,0 +1,49 @@ +use crate::escpos::{errors::EscPosError, job::Job}; +use std::io::Write; + +pub struct Printer { + pub queue: Vec, + pub max_width: u16, +} +impl Printer { + pub fn new(max_width: u16) -> Self { + Printer { + queue: Vec::new(), + max_width: max_width, + } + } + + pub fn new_job(&mut self) -> Result<&mut Job, EscPosError> { + self.queue.push(Job::new(self.max_width)); + self.queue.last_mut().ok_or(EscPosError::InvalidQueueIndex) + } + pub fn print_job(&mut self, writer: &mut impl Write) -> Result<(), EscPosError> { + // let page_feed: u8 = 0x0A; + let job = self + .queue + .extract_if(.., |j| j.ready) + .next() + .ok_or(EscPosError::EmptyQueue)?; + + // writer.write(&[page_feed]).unwrap(); // FIXME: remove unwraps + writer.write(&job.content).unwrap(); + // writer.write(&[page_feed]).unwrap(); + + Ok(()) + } + pub fn export_job(&mut self) -> Result, EscPosError> { + let page_feed: u8 = 0x0A; + let job = self + .queue + .extract_if(.., |j| j.ready) + .next() + .ok_or(EscPosError::EmptyQueue)?; + + let mut out = Vec::with_capacity(2 + job.content.len()); + out.push(page_feed); + out.extend(job.content); + out.push(page_feed); + + Ok(out) + } +} diff --git a/src/main.rs b/src/main.rs index 740f049..1a5f710 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,33 +4,38 @@ mod escpos; use image::{ImageError, ImageReader}; use std::{env, process}; -use crate::escpos::Printer; +use crate::escpos::{ + job::{BARTextPosition, BARType}, + printer::Printer, +}; fn main() { - let args: Vec = env::args().collect(); + // 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 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(); + let mut printer = Printer::new(384); let job = printer.new_job().unwrap(); - // job.write_qr("hi".to_string(), None, None).unwrap(); - job.write_barcode( - "hhhhhhhhhhh".to_string(), - None, - None, - None, - Some(escpos::BARType::UPCA), - ) - .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.ready = true;