Started implementing queues and escposprinter struct
This commit is contained in:
parent
410e203f9e
commit
fbf8111ddd
1 changed files with 119 additions and 35 deletions
114
src/escpos.rs
114
src/escpos.rs
|
|
@ -1,46 +1,130 @@
|
||||||
use crate::dithering::atkinson_mono;
|
use crate::dithering::atkinson_mono;
|
||||||
use image::{DynamicImage, imageops::FilterType};
|
use image::{DynamicImage, imageops::FilterType};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, VecDeque},
|
||||||
|
ops::{Add, AddAssign},
|
||||||
|
};
|
||||||
|
|
||||||
const MAX_WIDTH: u32 = 384;
|
const MAX_WIDTH: u32 = 384;
|
||||||
|
|
||||||
|
pub enum EscPosError {
|
||||||
|
InvalidBitmapMode,
|
||||||
|
InvalidQueueId,
|
||||||
|
}
|
||||||
pub enum ImageOrientation {
|
pub enum ImageOrientation {
|
||||||
Preserve,
|
Preserve,
|
||||||
Largest,
|
Largest,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn escpos_raster(
|
pub struct EscPosPrinter {
|
||||||
|
increment: u16,
|
||||||
|
queue: HashMap<u16, Vec<u8>>,
|
||||||
|
}
|
||||||
|
pub trait EscPosPrinterTrait {
|
||||||
|
fn new() -> EscPosPrinter;
|
||||||
|
fn new_job(&mut self) -> u16;
|
||||||
|
|
||||||
|
fn bitmap(
|
||||||
|
&mut self,
|
||||||
|
queue_id: u16,
|
||||||
img: &DynamicImage,
|
img: &DynamicImage,
|
||||||
orientation: Option<ImageOrientation>,
|
orientation: Option<ImageOrientation>,
|
||||||
mode: Option<u8>,
|
mode: Option<u8>,
|
||||||
) -> Vec<u8> {
|
) -> Result<(), EscPosError>;
|
||||||
|
fn qr(&mut self, queue_id: u16, text: String) -> Result<(), EscPosError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EscPosPrinterTrait for EscPosPrinter {
|
||||||
|
fn new() -> EscPosPrinter {
|
||||||
|
EscPosPrinter {
|
||||||
|
increment: 0,
|
||||||
|
queue: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_job(&mut self) -> u16 {
|
||||||
|
let job: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
self.increment.add_assign(1);
|
||||||
|
self.queue.insert(self.increment, job);
|
||||||
|
self.increment
|
||||||
|
}
|
||||||
|
fn print_job(&mut self, queue_id: u16) -> Result<(), EscPosError> {
|
||||||
|
let page_feed: u8 = 0x0A;
|
||||||
|
|
||||||
|
io::stdout().write(&page_feed);
|
||||||
|
io::stdout().write(&escpos).unwrap();
|
||||||
|
io::stdout().write(&page_feed).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bitmap(
|
||||||
|
&mut self,
|
||||||
|
queue_id: u16,
|
||||||
|
img: &DynamicImage,
|
||||||
|
orientation: Option<ImageOrientation>,
|
||||||
|
mode: Option<u8>,
|
||||||
|
) -> Result<(), EscPosError> {
|
||||||
let mode = mode.unwrap_or(0);
|
let mode = mode.unwrap_or(0);
|
||||||
assert!(mode <= 3 || (48..=51).contains(&mode));
|
if !(mode <= 3 || (48..=51).contains(&mode)) {
|
||||||
|
return Err(EscPosError::InvalidBitmapMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = self
|
||||||
|
.queue
|
||||||
|
.get_mut(&queue_id)
|
||||||
|
.ok_or(EscPosError::InvalidQueueId)?;
|
||||||
|
|
||||||
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(MAX_WIDTH) * w > w.min(MAX_WIDTH) * h;
|
||||||
|
|
||||||
let (w, h) = if swap { (h, w) } else { (w, h) };
|
let scale = if swap {
|
||||||
let (w, h) = (MAX_WIDTH, h.saturating_mul(MAX_WIDTH).div_ceil(w));
|
MAX_WIDTH as f32 / h as f32
|
||||||
|
} else {
|
||||||
|
MAX_WIDTH as f32 / w as f32
|
||||||
|
};
|
||||||
|
|
||||||
let img = if swap { &img.rotate90() } else { &img };
|
let (w, h) = if swap {
|
||||||
let img = img.resize(w, h, FilterType::Triangle);
|
((h as f32 * scale) as u32, MAX_WIDTH)
|
||||||
|
} else {
|
||||||
|
(MAX_WIDTH, (h as f32 * scale) as u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
let img =
|
||||||
|
DynamicImage::ImageRgba8(image::imageops::resize(img, w, h, FilterType::Triangle));
|
||||||
|
|
||||||
|
let img = if swap { img.rotate90() } else { img };
|
||||||
let mono = atkinson_mono(&img);
|
let mono = atkinson_mono(&img);
|
||||||
let (width_px, height_px) = (img.width() as u16, img.height() as u16);
|
let width_bytes = ((w + 7) >> 3) as u16;
|
||||||
let width_bytes = ((width_px + 7) >> 3) as u16;
|
|
||||||
|
|
||||||
let mut out = Vec::with_capacity(8 + mono.len());
|
buf.reserve(8 + mono.len());
|
||||||
out.extend_from_slice(&[
|
buf.extend_from_slice(&[
|
||||||
0x1D,
|
0x1D,
|
||||||
0x76,
|
0x76,
|
||||||
0x30,
|
0x30,
|
||||||
mode,
|
mode,
|
||||||
width_bytes as u8,
|
width_bytes as u8,
|
||||||
(width_bytes >> 8) as u8,
|
(width_bytes >> 8) as u8,
|
||||||
height_px as u8,
|
h as u8,
|
||||||
(height_px >> 8) as u8,
|
(h >> 8) as u8,
|
||||||
]);
|
]);
|
||||||
out.extend_from_slice(&mono);
|
buf.extend_from_slice(&mono);
|
||||||
out
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn qr(&mut self, queue_id: u16, text: String) -> Result<(), EscPosError> {
|
||||||
|
let buf = self
|
||||||
|
.queue
|
||||||
|
.get_mut(&queue_id)
|
||||||
|
.ok_or(EscPosError::InvalidQueueId)?;
|
||||||
|
|
||||||
|
let text = text.as_bytes();
|
||||||
|
buf.extend_from_slice(&[0x1C, 0x7D, 0x25, text.len() as u8]);
|
||||||
|
buf.extend(&text[..255]);
|
||||||
|
buf.extend(&[0x0A]);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue