Progress on modularizing escpos.
This commit is contained in:
parent
280d2fcbab
commit
be3fd25fcf
5 changed files with 103 additions and 84 deletions
7
src/escpos/errors.rs
Normal file
7
src/escpos/errors.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EscPosError {
|
||||||
|
EmptyQueue,
|
||||||
|
InvalidQueueIndex,
|
||||||
|
InvalidBitmapMode,
|
||||||
|
InvalidBarcodeLength(String),
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,5 @@
|
||||||
use crate::dithering::atkinson_mono;
|
use crate::{dithering::atkinson_mono, escpos::errors::EscPosError};
|
||||||
use image::{DynamicImage, imageops::FilterType};
|
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)]
|
#[repr(u8)]
|
||||||
pub enum QREcc {
|
pub enum QREcc {
|
||||||
|
|
@ -39,11 +28,9 @@ pub enum ImageOrientation {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Job {
|
pub struct Job {
|
||||||
content: Vec<u8>,
|
|
||||||
pub ready: bool,
|
pub ready: bool,
|
||||||
}
|
pub content: Vec<u8>,
|
||||||
pub struct Printer {
|
max_width: u16,
|
||||||
pub queue: Vec<Job>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_numeric(s: &[u8]) -> bool {
|
fn is_numeric(s: &[u8]) -> bool {
|
||||||
|
|
@ -51,10 +38,11 @@ fn is_numeric(s: &[u8]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Job {
|
impl Job {
|
||||||
pub fn new() -> Self {
|
pub fn new(max_width: u16) -> Self {
|
||||||
Job {
|
Job {
|
||||||
content: vec![0x1B, b'@'],
|
content: vec![0x1B, b'@'],
|
||||||
ready: false,
|
ready: false,
|
||||||
|
max_width: max_width,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,18 +59,18 @@ impl Job {
|
||||||
|
|
||||||
let (w, h) = (img.width(), img.height());
|
let (w, h) = (img.width(), img.height());
|
||||||
let swap = matches!(orientation, Some(ImageOrientation::Largest))
|
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 {
|
let scale = if swap {
|
||||||
MAX_WIDTH as f32 / h as f32
|
self.max_width as f32 / h as f32
|
||||||
} else {
|
} else {
|
||||||
MAX_WIDTH as f32 / w as f32
|
self.max_width as f32 / w as f32
|
||||||
};
|
};
|
||||||
|
|
||||||
let (w, h) = if swap {
|
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 {
|
} else {
|
||||||
(MAX_WIDTH, (h as f32 * scale) as u32)
|
(self.max_width as u32, (h as f32 * scale) as u32)
|
||||||
};
|
};
|
||||||
|
|
||||||
let img =
|
let img =
|
||||||
|
|
@ -95,6 +83,8 @@ impl Job {
|
||||||
let buf = &mut self.content;
|
let buf = &mut self.content;
|
||||||
buf.reserve(8 + mono.len());
|
buf.reserve(8 + mono.len());
|
||||||
buf.extend_from_slice(&[
|
buf.extend_from_slice(&[
|
||||||
|
0x1B,
|
||||||
|
b'@',
|
||||||
0x1D,
|
0x1D,
|
||||||
0x76,
|
0x76,
|
||||||
0x30,
|
0x30,
|
||||||
|
|
@ -124,6 +114,8 @@ impl Job {
|
||||||
let text = text.as_bytes();
|
let text = text.as_bytes();
|
||||||
let len = text.len() + 3;
|
let len = text.len() + 3;
|
||||||
buf.extend_from_slice(&[
|
buf.extend_from_slice(&[
|
||||||
|
0x1B,
|
||||||
|
b'@',
|
||||||
// Size
|
// Size
|
||||||
0x1D,
|
0x1D,
|
||||||
0x28,
|
0x28,
|
||||||
|
|
@ -186,6 +178,8 @@ impl Job {
|
||||||
|
|
||||||
let buf = &mut self.content;
|
let buf = &mut self.content;
|
||||||
buf.extend([
|
buf.extend([
|
||||||
|
0x1B,
|
||||||
|
b'@',
|
||||||
0x1D,
|
0x1D,
|
||||||
0x68,
|
0x68,
|
||||||
height,
|
height,
|
||||||
|
|
@ -205,42 +199,3 @@ impl Job {
|
||||||
Ok(())
|
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<Vec<u8>, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3
src/escpos/mod.rs
Normal file
3
src/escpos/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod errors;
|
||||||
|
pub mod job;
|
||||||
|
pub mod printer;
|
||||||
49
src/escpos/printer.rs
Normal file
49
src/escpos/printer.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
use crate::escpos::{errors::EscPosError, job::Job};
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
pub struct Printer {
|
||||||
|
pub queue: Vec<Job>,
|
||||||
|
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<Vec<u8>, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main.rs
49
src/main.rs
|
|
@ -4,33 +4,38 @@ mod escpos;
|
||||||
use image::{ImageError, ImageReader};
|
use image::{ImageError, ImageReader};
|
||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
|
|
||||||
use crate::escpos::Printer;
|
use crate::escpos::{
|
||||||
|
job::{BARTextPosition, BARType},
|
||||||
|
printer::Printer,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
// let args: Vec<String> = 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();
|
let mut printer = Printer::new(384);
|
||||||
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 job = printer.new_job().unwrap();
|
let job = printer.new_job().unwrap();
|
||||||
// job.write_qr("hi".to_string(), None, None).unwrap();
|
job.write_qr("https://pornhub.com".to_string(), None, None)
|
||||||
job.write_barcode(
|
// .unwrap();
|
||||||
"hhhhhhhhhhh".to_string(),
|
// job.write_barcode(
|
||||||
None,
|
// "kleintje".to_string(),
|
||||||
None,
|
// Some(10),
|
||||||
None,
|
// None,
|
||||||
Some(escpos::BARType::UPCA),
|
// Some(BARTextPosition::Both),
|
||||||
)
|
// Some(BARType::CODE128),
|
||||||
|
// )
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
job.content.extend_from_slice(&[b'\n', b'\n']);
|
||||||
// job.write_bitmap(&img, None, None).unwrap();
|
// job.write_bitmap(&img, None, None).unwrap();
|
||||||
job.ready = true;
|
job.ready = true;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue