Switch to persistent printer with queue
This commit is contained in:
parent
0ea4cf1d22
commit
6555e9c0bd
14 changed files with 221 additions and 76 deletions
|
|
@ -1,3 +1,4 @@
|
|||
mod backlog;
|
||||
mod calendar;
|
||||
mod cells;
|
||||
mod chat_message;
|
||||
|
|
@ -11,21 +12,23 @@ mod typst;
|
|||
use showbits_common::widgets::{FontStuff, HasFontStuff};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
pub use self::{
|
||||
calendar::CalendarDrawing, cells::CellsDrawing, chat_message::ChatMessageDrawing,
|
||||
egg::EggDrawing, image::ImageDrawing, photo::PhotoDrawing, text::TextDrawing,
|
||||
tictactoe::TicTacToeDrawing, typst::TypstDrawing,
|
||||
backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing,
|
||||
chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing, photo::PhotoDrawing,
|
||||
text::TextDrawing, tictactoe::TicTacToeDrawing, typst::TypstDrawing,
|
||||
};
|
||||
|
||||
pub const FEED: f32 = 64.0;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Context {
|
||||
font_stuff: FontStuff,
|
||||
}
|
||||
|
||||
pub trait Drawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()>;
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
pub struct Command(Box<dyn Drawing + Send>);
|
||||
|
|
@ -44,12 +47,12 @@ impl HasFontStuff for Context {
|
|||
|
||||
pub struct Drawer {
|
||||
rx: mpsc::Receiver<Command>,
|
||||
printer: Printer,
|
||||
printer: PersistentPrinter,
|
||||
ctx: Context,
|
||||
}
|
||||
|
||||
impl Drawer {
|
||||
pub fn new(rx: mpsc::Receiver<Command>, printer: Printer) -> Self {
|
||||
pub fn new(rx: mpsc::Receiver<Command>, printer: PersistentPrinter) -> Self {
|
||||
Self {
|
||||
rx,
|
||||
printer,
|
||||
|
|
|
|||
12
showbits-thermal-printer/src/drawer/backlog.rs
Normal file
12
showbits-thermal-printer/src/drawer/backlog.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
|
||||
pub struct BacklogDrawing;
|
||||
|
||||
impl Drawing for BacklogDrawing {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, _ctx: &mut Context) -> anyhow::Result<()> {
|
||||
printer.print_backlog()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,9 @@ use taffy::{
|
|||
style_helpers::{length, percent, repeat},
|
||||
};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct CalendarDrawing {
|
||||
pub year: i16,
|
||||
|
|
@ -19,7 +19,7 @@ pub struct CalendarDrawing {
|
|||
}
|
||||
|
||||
impl Drawing for CalendarDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut date = civil::Date::new(self.year, self.month, 1)?;
|
||||
|
||||
let mut tree = Tree::<Context>::new(WHITE);
|
||||
|
|
@ -86,6 +86,7 @@ impl Drawing for CalendarDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -94,7 +95,6 @@ impl Drawing for CalendarDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ use image::{
|
|||
imageops::{self, FilterType},
|
||||
};
|
||||
use showbits_common::{Node, Tree, WidgetExt, color, widgets::Image};
|
||||
use taffy::{AlignItems, Display, FlexDirection, style_helpers::percent};
|
||||
use taffy::{AlignItems, Display, FlexDirection, prelude::length, style_helpers::percent};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::{persistent_printer::PersistentPrinter, printer::Printer};
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
const BLACK: Rgba<u8> = Rgba([0, 0, 0, 255]);
|
||||
const WHITE: Rgba<u8> = Rgba([255, 255, 255, 255]);
|
||||
|
|
@ -49,8 +49,8 @@ pub struct CellsDrawing {
|
|||
}
|
||||
|
||||
impl Drawing for CellsDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut image = RgbaImage::new(Printer::WIDTH / self.scale, self.rows);
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut image: image::ImageBuffer<Rgba<u8>, Vec<u8>> = RgbaImage::new(Printer::WIDTH / self.scale, self.rows);
|
||||
|
||||
// Initialize first line randomly
|
||||
for x in 0..image.width() {
|
||||
|
|
@ -79,6 +79,7 @@ impl Drawing for CellsDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -86,7 +87,6 @@ impl Drawing for CellsDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use taffy::{
|
|||
style_helpers::{length, percent},
|
||||
};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ pub struct ChatMessageDrawing {
|
|||
}
|
||||
|
||||
impl Drawing for ChatMessageDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut tree = Tree::<Context>::new(WHITE);
|
||||
|
||||
let max_username_width_in_chars = 32.0;
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ use showbits_common::{
|
|||
color::{self, WHITE},
|
||||
widgets::{Image, Text},
|
||||
};
|
||||
use taffy::{AlignItems, Display, FlexDirection, style_helpers::percent};
|
||||
use taffy::{prelude::length, style_helpers::percent, AlignItems, Display, FlexDirection};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct EggDrawing;
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ fn load_image(bytes: &[u8]) -> RgbaImage {
|
|||
}
|
||||
|
||||
impl Drawing for EggDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut rng = rand::rng();
|
||||
|
||||
// Choose which set of egg images to use
|
||||
|
|
@ -84,6 +84,7 @@ impl Drawing for EggDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -92,7 +93,6 @@ impl Drawing for EggDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use showbits_common::{
|
|||
color::{self, BLACK, WHITE},
|
||||
widgets::{DitherAlgorithm, Image},
|
||||
};
|
||||
use taffy::{AlignItems, Display, FlexDirection, style_helpers::percent};
|
||||
use taffy::{AlignItems, Display, FlexDirection, prelude::length, style_helpers::percent};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct ImageDrawing {
|
||||
pub image: RgbaImage,
|
||||
|
|
@ -19,7 +19,7 @@ pub struct ImageDrawing {
|
|||
}
|
||||
|
||||
impl Drawing for ImageDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut image = self.image.clone();
|
||||
if self.bright {
|
||||
for pixel in image.pixels_mut() {
|
||||
|
|
@ -40,6 +40,7 @@ impl Drawing for ImageDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -47,7 +48,6 @@ impl Drawing for ImageDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ use taffy::{
|
|||
style_helpers::{length, percent},
|
||||
};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct PhotoDrawing {
|
||||
pub image: RgbaImage,
|
||||
|
|
@ -19,7 +19,7 @@ pub struct PhotoDrawing {
|
|||
}
|
||||
|
||||
impl Drawing for PhotoDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut tree = Tree::<Context>::new(WHITE);
|
||||
|
||||
let mut image = self.image.clone();
|
||||
|
|
@ -45,6 +45,7 @@ impl Drawing for PhotoDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -54,7 +55,6 @@ impl Drawing for PhotoDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use showbits_common::{Node, Tree, WidgetExt, color::WHITE, widgets::Text};
|
||||
use taffy::style_helpers::percent;
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
|
||||
pub struct TextDrawing(pub String);
|
||||
|
||||
impl Drawing for TextDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut tree = Tree::<Context>::new(WHITE);
|
||||
|
||||
let text = Text::new()
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ use taffy::{
|
|||
style_helpers::{length, percent, repeat},
|
||||
};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct TicTacToeDrawing;
|
||||
|
||||
impl Drawing for TicTacToeDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let block_size = length(128.0);
|
||||
let width = length(2.0);
|
||||
|
||||
|
|
@ -57,6 +57,7 @@ impl Drawing for TicTacToeDrawing {
|
|||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.with_display(Display::Flex)
|
||||
.with_flex_direction(FlexDirection::Column)
|
||||
.with_align_items(Some(AlignItems::Center))
|
||||
|
|
@ -66,7 +67,6 @@ impl Drawing for TicTacToeDrawing {
|
|||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
use showbits_common::{Node, Tree, WidgetExt, color::WHITE, widgets::Typst};
|
||||
use taffy::style_helpers::percent;
|
||||
use taffy::{prelude::length, style_helpers::percent};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::persistent_printer::PersistentPrinter;
|
||||
|
||||
use super::{Context, Drawing};
|
||||
use super::{Context, Drawing, FEED};
|
||||
|
||||
pub struct TypstDrawing(pub String);
|
||||
|
||||
impl Drawing for TypstDrawing {
|
||||
fn draw(&self, printer: &mut Printer, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
||||
let mut tree = Tree::<Context>::new(WHITE);
|
||||
|
||||
let typst = Typst::new(self.0.clone()).node().register(&mut tree)?;
|
||||
|
||||
let root = Node::empty()
|
||||
.with_size_width(percent(1.0))
|
||||
.with_padding_bottom(length(FEED))
|
||||
.and_child(typst)
|
||||
.register(&mut tree)?;
|
||||
|
||||
printer.print_tree(&mut tree, ctx, root)?;
|
||||
printer.feed()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,24 @@
|
|||
mod drawer;
|
||||
mod persistent_printer;
|
||||
mod printer;
|
||||
mod server;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
use clap::Parser;
|
||||
use drawer::Drawer;
|
||||
use printer::Printer;
|
||||
use drawer::{BacklogDrawing, Command};
|
||||
use tokio::{runtime::Runtime, sync::mpsc};
|
||||
|
||||
use self::{drawer::Drawer, persistent_printer::PersistentPrinter};
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
/// Address the web server will listen at.
|
||||
addr: String,
|
||||
|
||||
/// Path to the queue directory.
|
||||
queue: PathBuf,
|
||||
|
||||
/// Path to the printer's USB device file.
|
||||
///
|
||||
/// Usually, this is located at `/dev/usb/lp0` or a similar location.
|
||||
|
|
@ -30,11 +35,17 @@ fn main() -> anyhow::Result<()> {
|
|||
|
||||
let (tx, rx) = mpsc::channel(3);
|
||||
|
||||
let printer = Printer::new(args.printer, args.export)?;
|
||||
let printer = PersistentPrinter::new(args.printer, args.export, args.queue);
|
||||
let mut drawer = Drawer::new(rx, printer);
|
||||
|
||||
let runtime = Runtime::new()?;
|
||||
runtime.spawn(server::run(tx, args.addr));
|
||||
runtime.spawn(server::run(tx.clone(), args.addr));
|
||||
runtime.spawn(async move {
|
||||
loop {
|
||||
let _ = tx.send(Command::draw(BacklogDrawing)).await;
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
|
||||
println!("Running");
|
||||
drawer.run()?;
|
||||
|
|
|
|||
135
showbits-thermal-printer/src/persistent_printer.rs
Normal file
135
showbits-thermal-printer/src/persistent_printer.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use std::{fs, io::ErrorKind, path::PathBuf};
|
||||
|
||||
use anyhow::{Context, bail};
|
||||
use image::RgbaImage;
|
||||
use jiff::Timestamp;
|
||||
use showbits_common::Tree;
|
||||
use taffy::{AvailableSpace, NodeId, Size};
|
||||
|
||||
use crate::printer::Printer;
|
||||
|
||||
pub struct PersistentPrinter {
|
||||
printer_file: Option<PathBuf>,
|
||||
export_file: Option<PathBuf>,
|
||||
queue_dir: PathBuf,
|
||||
|
||||
printer: Option<Printer>,
|
||||
}
|
||||
|
||||
impl PersistentPrinter {
|
||||
pub fn new(
|
||||
printer_file: Option<PathBuf>,
|
||||
export_file: Option<PathBuf>,
|
||||
queue_dir: PathBuf,
|
||||
) -> Self {
|
||||
Self {
|
||||
printer_file,
|
||||
export_file,
|
||||
queue_dir,
|
||||
printer: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn render_tree_to_image<C>(
|
||||
tree: &mut Tree<C>,
|
||||
ctx: &mut C,
|
||||
root: NodeId,
|
||||
) -> anyhow::Result<RgbaImage> {
|
||||
let available = Size {
|
||||
width: AvailableSpace::Definite(Printer::WIDTH as f32),
|
||||
// TODO Maybe MinContent? If not, why not?
|
||||
height: AvailableSpace::MaxContent,
|
||||
};
|
||||
|
||||
tree.render(ctx, root, available)
|
||||
}
|
||||
|
||||
fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
||||
let Some(printer) = &mut self.printer else {
|
||||
bail!("no printer found");
|
||||
};
|
||||
printer.print_image(image)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reconnect_printer(&mut self) -> anyhow::Result<()> {
|
||||
let printer = Printer::new(self.printer_file.clone(), self.export_file.clone())?;
|
||||
self.printer = Some(printer);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
||||
println!("Printing image");
|
||||
if self.print_image(image).is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
println!("First attempt failed, reconnecting and retrying");
|
||||
self.reconnect_printer()?;
|
||||
self.print_image(image)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enqueue_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
||||
let now = Timestamp::now();
|
||||
let path = self.queue_dir.join(format!("{now}.png"));
|
||||
println!("Enqueuing image {}", path.display());
|
||||
|
||||
fs::create_dir_all(&self.queue_dir)
|
||||
.with_context(|| format!("At {}", self.queue_dir.display()))
|
||||
.context("Failed to create queue directory")?;
|
||||
|
||||
image
|
||||
.save(&path)
|
||||
.with_context(|| format!("At {}", path.display()))
|
||||
.context("Failed to save image to queue")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_tree<C>(
|
||||
&mut self,
|
||||
tree: &mut Tree<C>,
|
||||
ctx: &mut C,
|
||||
root: NodeId,
|
||||
) -> anyhow::Result<()> {
|
||||
let image = Self::render_tree_to_image(tree, ctx, root)?;
|
||||
if self.print_image_robustly(&image).is_err() {
|
||||
self.enqueue_image(&image)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_backlog(&mut self) -> anyhow::Result<()> {
|
||||
let mut files = vec![];
|
||||
|
||||
match self.queue_dir.read_dir() {
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => {}
|
||||
|
||||
Err(err) => Err(err)
|
||||
.with_context(|| format!("At {}", self.queue_dir.display()))
|
||||
.context("Failed to open queue dir")?,
|
||||
|
||||
Ok(dir) => {
|
||||
for entry in dir {
|
||||
let entry = entry?;
|
||||
if entry.file_type()?.is_file() {
|
||||
files.push(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
files.sort_unstable();
|
||||
|
||||
for file in files {
|
||||
println!("Dequeuing image {}", file.display());
|
||||
let image: RgbaImage = image::open(&file)?.into_rgba8();
|
||||
if self.print_image_robustly(&image).is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
fs::remove_file(&file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use escpos::{
|
||||
driver::FileDriver,
|
||||
printer::Printer as EPrinter,
|
||||
|
|
@ -7,8 +8,7 @@ use escpos::{
|
|||
utils::{GS, PageCode, Protocol},
|
||||
};
|
||||
use image::{Rgba, RgbaImage};
|
||||
use showbits_common::{Tree, color};
|
||||
use taffy::{AvailableSpace, NodeId, Size};
|
||||
use showbits_common::color;
|
||||
|
||||
pub struct Printer {
|
||||
printer: Option<EPrinter<FileDriver>>,
|
||||
|
|
@ -44,7 +44,9 @@ impl Printer {
|
|||
export_path: Option<PathBuf>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let printer = if let Some(path) = printer_path {
|
||||
let driver = FileDriver::open(&path)?;
|
||||
let driver = FileDriver::open(&path)
|
||||
.with_context(|| format!("At {}", path.display()))
|
||||
.context("Failed to open printer driver")?;
|
||||
let protocol = Protocol::default();
|
||||
let mut options = PrinterOptions::default();
|
||||
options.page_code(Some(Self::PAGE_CODE));
|
||||
|
|
@ -59,34 +61,16 @@ impl Printer {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn feed(&mut self) -> anyhow::Result<()> {
|
||||
if let Some(printer) = &mut self.printer {
|
||||
printer.init()?.feeds(3)?.print()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_tree<C>(
|
||||
&mut self,
|
||||
tree: &mut Tree<C>,
|
||||
ctx: &mut C,
|
||||
root: NodeId,
|
||||
) -> anyhow::Result<()> {
|
||||
let available = Size {
|
||||
width: AvailableSpace::Definite(Self::WIDTH as f32),
|
||||
// TODO Maybe MinContent? If not, why not?
|
||||
height: AvailableSpace::MaxContent,
|
||||
};
|
||||
|
||||
let image = tree.render(ctx, root, available)?;
|
||||
|
||||
pub fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
||||
if let Some(path) = &self.export_path {
|
||||
image.save(path)?;
|
||||
image
|
||||
.save(path)
|
||||
.with_context(|| format!("At {}", path.display()))
|
||||
.context("Failed to export to-be-printed image")?;
|
||||
}
|
||||
|
||||
if let Some(printer) = &mut self.printer {
|
||||
Self::print_image_to_printer(printer, &image)?;
|
||||
Self::print_image_to_printer(printer, image).context("Failed to print image")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue