1use super::errors::Result;
4#[cfg(feature = "ui")]
5use crate::domain::ui::line::Line;
6use crate::printer_options::PrinterOptions;
7use crate::{domain::*, driver::Driver, utils::Protocol};
8use log::debug;
9
10#[derive(Clone)]
33pub struct Printer<D: Driver> {
34 driver: D,
35 protocol: Protocol,
36 options: PrinterOptions,
37 instructions: Vec<Instruction>,
38 style_state: PrinterStyleState,
39}
40
41impl<D: Driver> Printer<D> {
42 pub fn new(driver: D, protocol: Protocol, options: Option<PrinterOptions>) -> Self {
61 Self {
62 driver,
63 protocol,
64 options: options.unwrap_or_default(),
65 instructions: vec![],
66 style_state: PrinterStyleState::default(),
67 }
68 }
69
70 pub fn protocol(&self) -> &Protocol {
72 &self.protocol
73 }
74
75 pub fn options(&self) -> &PrinterOptions {
77 &self.options
78 }
79
80 pub fn style_state(&self) -> PrinterStyleState {
115 self.style_state.clone()
116 }
117
118 pub fn reset_style_state(&mut self) -> &mut Self {
120 self.style_state = PrinterStyleState::default();
121 self
122 }
123
124 fn flush(&mut self) -> Result<&mut Self> {
126 for instruction in self.instructions.iter() {
127 self.driver.write(&instruction.flatten_commands())?
128 }
129 self.driver.flush()?;
130 self.instructions = vec![];
131 self.reset_style_state();
132
133 Ok(self)
134 }
135
136 pub fn debug_mode(&mut self, mode: Option<DebugMode>) -> &mut Self {
138 self.options.debug_mode(mode);
139 self
140 }
141
142 pub fn print(&mut self) -> Result<&mut Self> {
147 self.flush()?;
148
149 if self.options.get_debug_mode().is_some() {
150 debug!("[print]");
151 }
152
153 Ok(self)
154 }
155
156 fn command(&mut self, label: &str, cmd: &[Command]) -> Result<&mut Self> {
158 let instruction = Instruction::new(label, cmd, self.options.get_debug_mode());
159
160 if !label.is_empty() && self.options.get_debug_mode().is_some() {
161 debug!("{:?}", instruction.clone());
162 }
163
164 self.instructions.push(instruction);
165
166 Ok(self)
167 }
168
169 pub fn init(&mut self) -> Result<&mut Self> {
171 let cmd = self.protocol.init();
172 self.command("initialization", &[cmd])?;
173
174 if let Some(page_code) = self.options.get_page_code() {
176 let cmd = self.protocol.page_code(page_code);
177 self.command("character page code", &[cmd])?;
178 }
179
180 Ok(self)
181 }
182
183 pub fn reset(&mut self) -> Result<&mut Self> {
185 let cmd = self.protocol.reset();
186 self.command("reset", &[cmd])
187 }
188
189 pub fn cut(&mut self) -> Result<&mut Self> {
191 let cmd = self.protocol.cut(false);
192 self.command("full paper cut", &[cmd])
193 }
194
195 pub fn partial_cut(&mut self) -> Result<&mut Self> {
197 let cmd = self.protocol.cut(true);
198 self.command("partial paper cut", &[cmd])
199 }
200
201 pub fn print_cut(&mut self) -> Result<&mut Self> {
203 let cmd = self.protocol.cut(false);
204 self.command("full paper cut", &[cmd])?.print()
205 }
206
207 pub fn page_code(&mut self, code: PageCode) -> Result<&mut Self> {
209 self.options.page_code(Some(code));
210
211 let cmd = self.protocol.page_code(code);
212 self.command("character page code", &[cmd])
213 }
214
215 pub fn character_set(&mut self, code: CharacterSet) -> Result<&mut Self> {
217 let cmd = self.protocol.character_set(code);
218 self.command("international character set", &[cmd])
219 }
220
221 pub fn bold(&mut self, enabled: bool) -> Result<&mut Self> {
223 let cmd = self.protocol.bold(enabled);
224 self.style_state.bold = enabled;
225 self.command("text bold", &[cmd])
226 }
227
228 pub fn underline(&mut self, mode: UnderlineMode) -> Result<&mut Self> {
230 let cmd = self.protocol.underline(mode);
231 self.style_state.underline_mode = mode;
232 self.command("text underline", &[cmd])
233 }
234
235 pub fn double_strike(&mut self, enabled: bool) -> Result<&mut Self> {
237 let cmd = self.protocol.double_strike(enabled);
238 self.style_state.double_strike = enabled;
239 self.command("text double strike", &[cmd])
240 }
241
242 pub fn font(&mut self, font: Font) -> Result<&mut Self> {
244 let cmd = self.protocol.font(font);
245 self.style_state.font = font;
246 self.command("text font", &[cmd])
247 }
248
249 pub fn flip(&mut self, enabled: bool) -> Result<&mut Self> {
251 let cmd = self.protocol.flip(enabled);
252 self.style_state.flip = enabled;
253 self.command("text flip", &[cmd])
254 }
255
256 pub fn justify(&mut self, mode: JustifyMode) -> Result<&mut Self> {
258 let cmd = self.protocol.justify(mode);
259 self.style_state.justify_mode = mode;
260 self.command("text justify", &[cmd])
261 }
262
263 pub fn reverse(&mut self, enabled: bool) -> Result<&mut Self> {
265 let cmd = self.protocol.reverse_colours(enabled);
266 self.style_state.reverse = enabled;
267 self.command("text reverse colour", &[cmd])
268 }
269
270 pub fn size(&mut self, width: u8, height: u8) -> Result<&mut Self> {
272 let cmd = self.protocol.text_size(width, height)?;
273 self.style_state.text_size = (width, height);
274 self.command("text size", &[cmd])
275 }
276
277 pub fn reset_size(&mut self) -> Result<&mut Self> {
279 let cmd = self.protocol.text_size(1, 1)?;
280 self.style_state.text_size = (1, 1);
281 self.command("text size", &[cmd])
282 }
283
284 pub fn smoothing(&mut self, enabled: bool) -> Result<&mut Self> {
286 let cmd = self.protocol.smoothing(enabled);
287 self.command("smoothing mode", &[cmd])
288 }
289
290 pub fn feed(&mut self) -> Result<&mut Self> {
292 let cmd = self.protocol.feed(1);
293 self.command("line feed", &[cmd])
294 }
295
296 pub fn feeds(&mut self, lines: u8) -> Result<&mut Self> {
298 let cmd = self.protocol.feed(lines);
299 self.command("line feeds", &[cmd])
300 }
301
302 pub fn line_spacing(&mut self, value: u8) -> Result<&mut Self> {
304 let cmd = self.protocol.line_spacing(value);
305 self.command("line spacing", &[cmd])
306 }
307
308 pub fn reset_line_spacing(&mut self) -> Result<&mut Self> {
310 let cmd = self.protocol.reset_line_spacing();
311 self.command("reset line spacing", &[cmd])
312 }
313
314 pub fn upside_down(&mut self, enabled: bool) -> Result<&mut Self> {
316 let cmd = self.protocol.upside_down(enabled);
317 self.command("upside-down mode", &[cmd])
318 }
319
320 pub fn cash_drawer(&mut self, pin: CashDrawer) -> Result<&mut Self> {
322 let cmd = self.protocol.cash_drawer(pin);
323 self.command("cash drawer", &[cmd])
324 }
325
326 pub fn write(&mut self, text: &str) -> Result<&mut Self> {
328 let cmd = self.protocol.text(text, self.options.get_page_code(), None)?;
329 self.command("text", &[cmd])
330 }
331
332 pub fn writeln(&mut self, text: &str) -> Result<&mut Self> {
334 self.write(text)?.feed()
335 }
336
337 pub fn custom(&mut self, cmd: &[u8]) -> Result<&mut Self> {
359 self.command("custom command", &[cmd.to_vec()])
360 }
361
362 pub fn custom_with_page_code(&mut self, cmd: &[u8], page_code: PageCode) -> Result<&mut Self> {
384 self.page_code(page_code)?;
385 self.command(&format!("custom command width page code {page_code}"), &[cmd.to_vec()])
386 }
387
388 pub fn motion_units(&mut self, x: u8, y: u8) -> Result<&mut Self> {
390 let cmd = self.protocol.motion_units(x, y);
391 self.command("set motion units", &[cmd])
392 }
393
394 pub fn real_time_status(&mut self, status: RealTimeStatusRequest) -> Result<&mut Self> {
396 let cmd = self.protocol.real_time_status(status);
397 self.command("real-time status", &[cmd])
398 }
399
400 pub fn send_status(&mut self) -> Result<&mut Self> {
402 self.flush()?;
403
404 if self.options.get_debug_mode().is_some() {
405 debug!("[send printer status]");
406 }
407
408 Ok(self)
409 }
410
411 #[cfg(feature = "barcodes")]
412 fn barcode(&mut self, barcode: Barcode) -> Result<&mut Self> {
414 let commands = self.protocol.barcode(&barcode.data, barcode.system, barcode.option)?;
415 self.command(&format!("print {} barcode", barcode.system), commands.as_slice())
416 }
417
418 #[cfg(feature = "barcodes")]
419 pub fn ean13(&mut self, data: &str) -> Result<&mut Self> {
421 self.barcode(Barcode::new(BarcodeSystem::EAN13, data, BarcodeOption::default())?)
422 }
423
424 #[cfg(feature = "barcodes")]
425 pub fn ean13_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
427 self.barcode(Barcode::new(BarcodeSystem::EAN13, data, option)?)
428 }
429
430 #[cfg(feature = "barcodes")]
431 pub fn ean8(&mut self, data: &str) -> Result<&mut Self> {
433 self.barcode(Barcode::new(BarcodeSystem::EAN8, data, BarcodeOption::default())?)
434 }
435
436 #[cfg(feature = "barcodes")]
437 pub fn ean8_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
439 self.barcode(Barcode::new(BarcodeSystem::EAN8, data, option)?)
440 }
441
442 #[cfg(feature = "barcodes")]
443 pub fn upca(&mut self, data: &str) -> Result<&mut Self> {
445 self.barcode(Barcode::new(BarcodeSystem::UPCA, data, BarcodeOption::default())?)
446 }
447
448 #[cfg(feature = "barcodes")]
449 pub fn upca_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
451 self.barcode(Barcode::new(BarcodeSystem::UPCA, data, option)?)
452 }
453
454 #[cfg(feature = "barcodes")]
455 pub fn upce(&mut self, data: &str) -> Result<&mut Self> {
457 self.barcode(Barcode::new(BarcodeSystem::UPCE, data, BarcodeOption::default())?)
458 }
459
460 #[cfg(feature = "barcodes")]
461 pub fn upce_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
463 self.barcode(Barcode::new(BarcodeSystem::UPCE, data, option)?)
464 }
465
466 #[cfg(feature = "barcodes")]
467 pub fn code39(&mut self, data: &str) -> Result<&mut Self> {
469 self.barcode(Barcode::new(BarcodeSystem::CODE39, data, BarcodeOption::default())?)
470 }
471
472 #[cfg(feature = "barcodes")]
473 pub fn code39_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
475 self.barcode(Barcode::new(BarcodeSystem::CODE39, data, option)?)
476 }
477
478 #[cfg(feature = "barcodes")]
479 pub fn codabar(&mut self, data: &str) -> Result<&mut Self> {
481 self.barcode(Barcode::new(BarcodeSystem::CODABAR, data, BarcodeOption::default())?)
482 }
483
484 #[cfg(feature = "barcodes")]
485 pub fn codabar_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
487 self.barcode(Barcode::new(BarcodeSystem::CODABAR, data, option)?)
488 }
489
490 #[cfg(feature = "barcodes")]
491 pub fn itf(&mut self, data: &str) -> Result<&mut Self> {
493 self.barcode(Barcode::new(BarcodeSystem::ITF, data, BarcodeOption::default())?)
494 }
495
496 #[cfg(feature = "barcodes")]
497 pub fn itf_option(&mut self, data: &str, option: BarcodeOption) -> Result<&mut Self> {
499 self.barcode(Barcode::new(BarcodeSystem::ITF, data, option)?)
500 }
501
502 #[cfg(feature = "codes_2d")]
503 fn qrcode_builder(&mut self, data: &str, option: Option<QRCodeOption>) -> Result<&mut Self> {
505 let qrcode = QRCode::new(data, option)?;
506 let commands = self.protocol.qrcode(&qrcode.data, qrcode.option)?;
507 self.command("print qrcode", commands.as_slice())
508 }
509
510 #[cfg(feature = "codes_2d")]
511 pub fn qrcode(&mut self, data: &str) -> Result<&mut Self> {
513 self.qrcode_builder(data, None)
514 }
515
516 #[cfg(feature = "codes_2d")]
517 pub fn qrcode_option(&mut self, data: &str, option: QRCodeOption) -> Result<&mut Self> {
519 self.qrcode_builder(data, Some(option))
520 }
521
522 #[cfg(feature = "codes_2d")]
523 pub fn gs1_databar_2d_option(&mut self, data: &str, option: GS1DataBar2DOption) -> Result<&mut Self> {
525 let code = GS1DataBar2D::new(data, option)?;
526 let commands = self.protocol.gs1_databar_2d(&code.data, code.option)?;
527 self.command("print 2D GS1 DataBar", commands.as_slice())
528 }
529
530 #[cfg(feature = "codes_2d")]
531 pub fn gs1_databar_2d(&mut self, data: &str) -> Result<&mut Self> {
533 self.gs1_databar_2d_option(data, GS1DataBar2DOption::default())
534 }
535
536 #[cfg(feature = "codes_2d")]
537 pub fn pdf417_option(&mut self, data: &str, option: Pdf417Option) -> Result<&mut Self> {
539 let code = Pdf417::new(data, option);
540 let commands = self.protocol.pdf417(&code.data, code.option)?;
541 self.command("print PDF417", commands.as_slice())
542 }
543
544 #[cfg(feature = "codes_2d")]
545 pub fn pdf417(&mut self, data: &str) -> Result<&mut Self> {
547 let code = Pdf417::new(data, Pdf417Option::default());
548 self.pdf417_option(data, code.option)
549 }
550
551 #[cfg(feature = "codes_2d")]
552 pub fn maxi_code_option(&mut self, data: &str, mode: MaxiCodeMode) -> Result<&mut Self> {
554 let code = MaxiCode::new(data, mode);
555 let commands = self.protocol.maxi_code(&code.data, code.mode)?;
556 self.command("print MaxiCode", commands.as_slice())
557 }
558
559 #[cfg(feature = "codes_2d")]
560 pub fn maxi_code(&mut self, data: &str) -> Result<&mut Self> {
562 let code = MaxiCode::new(data, MaxiCodeMode::default());
563 self.maxi_code_option(data, code.mode)
564 }
565
566 #[cfg(feature = "codes_2d")]
567 pub fn data_matrix_option(&mut self, data: &str, option: DataMatrixOption) -> Result<&mut Self> {
569 let code = DataMatrix::new(data, option);
570 let commands = self.protocol.data_matrix(&code.data, code.option)?;
571 self.command("print DataMatrix", commands.as_slice())
572 }
573
574 #[cfg(feature = "codes_2d")]
575 pub fn data_matrix(&mut self, data: &str) -> Result<&mut Self> {
577 let code = DataMatrix::new(data, DataMatrixOption::default());
578 self.data_matrix_option(data, code.option)
579 }
580
581 #[cfg(feature = "codes_2d")]
582 pub fn aztec_option(&mut self, data: &str, option: AztecOption) -> Result<&mut Self> {
584 let code = Aztec::new(data, option);
585 let commands = self.protocol.aztec(&code.data, code.option)?;
586 self.command("print Aztec", commands.as_slice())
587 }
588
589 #[cfg(feature = "codes_2d")]
590 pub fn aztec(&mut self, data: &str) -> Result<&mut Self> {
592 let code = Aztec::new(data, AztecOption::default());
593 self.aztec_option(data, code.option)
594 }
595
596 #[cfg(feature = "graphics")]
597 pub fn bit_image_option(&mut self, path: &str, option: BitImageOption) -> Result<&mut Self> {
599 let cmd = self.protocol.cancel();
600 self.command("cancel data", &[cmd])?;
601
602 let cmd = self.protocol.bit_image(path, option)?;
603 self.command("print bit image", &[cmd])
604 }
605
606 #[cfg(feature = "graphics")]
607 pub fn bit_image(&mut self, path: &str) -> Result<&mut Self> {
609 self.bit_image_option(path, BitImageOption::default())
610 }
611
612 #[cfg(feature = "graphics")]
613 pub fn bit_image_from_bytes_option(&mut self, bytes: &[u8], option: BitImageOption) -> Result<&mut Self> {
615 let cmd = self.protocol.cancel();
616 self.command("cancel data", &[cmd])?;
617
618 let cmd = self.protocol.bit_image_from_bytes(bytes, option)?;
619 self.command("print bit image from bytes", &[cmd])
620 }
621
622 #[cfg(feature = "graphics")]
623 pub fn bit_image_from_bytes(&mut self, bytes: &[u8]) -> Result<&mut Self> {
625 self.bit_image_from_bytes_option(bytes, BitImageOption::default())
626 }
627
628 #[cfg(feature = "ui")]
629 pub fn draw_line(&mut self, line: Line) -> Result<&mut Self> {
631 let commands = self
632 .protocol
633 .draw_line(line, self.options.clone(), self.style_state.clone())?;
634 self.command("draw line", commands.as_slice())
635 }
636
637 }
651
652#[derive(Debug, Clone, PartialEq)]
653pub struct PrinterStyleState {
654 pub text_size: (u8, u8),
655 pub justify_mode: JustifyMode,
656 pub font: Font,
657 pub underline_mode: UnderlineMode,
658 pub bold: bool,
659 pub double_strike: bool,
660 pub reverse: bool,
661 pub flip: bool,
662}
663
664impl Default for PrinterStyleState {
665 fn default() -> Self {
666 Self {
667 text_size: (1, 1),
668 justify_mode: JustifyMode::default(),
669 font: Font::default(),
670 underline_mode: UnderlineMode::default(),
671 bold: false,
672 double_strike: false,
673 reverse: false,
674 flip: false,
675 }
676 }
677}
678
679impl PrinterStyleState {}
680
681#[cfg(test)]
682mod tests {
683 use super::*;
684 use crate::driver::ConsoleDriver;
685
686 #[test]
687 fn test_command() {
688 let driver = ConsoleDriver::open(false);
689 let debug_mode = None;
690 let mut printer = Printer::new(driver, Protocol::default(), None);
691 printer.debug_mode(debug_mode).init().unwrap();
692 let cmd = printer.protocol.cut(false);
693 let printer = printer.command("test paper cut", &[cmd]).unwrap();
694
695 let expected = vec![
696 Instruction::new("initialization", &[vec![27, 64]], debug_mode),
697 Instruction::new("test paper cut", &[vec![29, 86, 65, 0]], debug_mode),
698 ];
699
700 assert_eq!(printer.instructions, expected);
701 }
702}