From 428b825e431ead07be312dfbf355c0f0453220ec Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 28 Feb 2025 23:10:31 +0100 Subject: [PATCH] Use new typst rendering in /test endpoint --- .vscode/settings.json | 7 ++++--- Cargo.lock | 1 + Cargo.toml | 1 + showbits-thermal-printer/Cargo.toml | 1 + showbits-thermal-printer/src/documents.rs | 9 ++++++++ .../src/documents/lib.typ | 21 +++++++++++++++++++ .../src/documents/text/data.json | 5 +++++ .../src/documents/text/lib.typ | 1 + .../src/documents/text/main.typ | 13 ++++++++++++ .../src/documents/text/mod.rs | 19 +++++++++++++++++ showbits-thermal-printer/src/drawer.rs | 6 ++++-- .../src/drawer/new_typst.rs | 21 +++++++++++++++++++ showbits-thermal-printer/src/main.rs | 1 + .../src/persistent_printer.rs | 17 +++++++++------ showbits-thermal-printer/src/server.rs | 19 ++++++++++++++--- 15 files changed, 128 insertions(+), 14 deletions(-) create mode 100644 showbits-thermal-printer/src/documents.rs create mode 100644 showbits-thermal-printer/src/documents/lib.typ create mode 100644 showbits-thermal-printer/src/documents/text/data.json create mode 120000 showbits-thermal-printer/src/documents/text/lib.typ create mode 100644 showbits-thermal-printer/src/documents/text/main.typ create mode 100644 showbits-thermal-printer/src/documents/text/mod.rs create mode 100644 showbits-thermal-printer/src/drawer/new_typst.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index a353aad..cb6d475 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { - "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - } + "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "tinymist.fontPaths": ["showbits-assets/data"] } diff --git a/Cargo.lock b/Cargo.lock index 89d15e5..618793d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2514,6 +2514,7 @@ dependencies = [ "serde", "showbits-assets", "showbits-common", + "showbits-typst", "taffy", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 83cd0fd..4806234 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ rust-embed = "8.5.0" serde = { version = "1.0.218", features = ["derive"] } showbits-assets.path = "./showbits-assets" showbits-common.path = "./showbits-common" +showbits-typst.path = "./showbits-typst" tokio = "1.43.0" typst = "0.13.0" typst-assets = { version = "0.13.0", features = ["fonts"] } diff --git a/showbits-thermal-printer/Cargo.toml b/showbits-thermal-printer/Cargo.toml index 263eec7..9a87c7d 100644 --- a/showbits-thermal-printer/Cargo.toml +++ b/showbits-thermal-printer/Cargo.toml @@ -17,6 +17,7 @@ rust-embed = { workspace = true } serde = { workspace = true } showbits-assets = { workspace = true } showbits-common = { workspace = true } +showbits-typst = { workspace = true } taffy = { workspace = true } tokio = { workspace = true, features = ["full"] } diff --git a/showbits-thermal-printer/src/documents.rs b/showbits-thermal-printer/src/documents.rs new file mode 100644 index 0000000..0ad992f --- /dev/null +++ b/showbits-thermal-printer/src/documents.rs @@ -0,0 +1,9 @@ +use showbits_typst::Typst; + +pub use self::text::*; + +mod text; + +fn typst_with_lib() -> Typst { + Typst::new().with_file("/lib.typ", include_str!("documents/lib.typ")) +} diff --git a/showbits-thermal-printer/src/documents/lib.typ b/showbits-thermal-printer/src/documents/lib.typ new file mode 100644 index 0000000..69f55ca --- /dev/null +++ b/showbits-thermal-printer/src/documents/lib.typ @@ -0,0 +1,21 @@ +#let init(it) = { + set page( + width: 384pt, + height: auto, + margin: (x: 0pt, y: 4pt), + ) + set text( + font: ("Unifont", "Unifont-JP", "Unifont Upper"), + size: 16pt, + fallback: false, + ) + set par( + leading: 8pt, // Between lines + spacing: 26pt, // Between paragraphs + ) + it +} + +// Determined by experiments so that the top and bottom white border are roughly +// the same size after tearing off the paper. +#let feed = v(64pt + 32pt) diff --git a/showbits-thermal-printer/src/documents/text/data.json b/showbits-thermal-printer/src/documents/text/data.json new file mode 100644 index 0000000..90b843b --- /dev/null +++ b/showbits-thermal-printer/src/documents/text/data.json @@ -0,0 +1,5 @@ +{ + "text": "Hello world! äöüßÄÖÜẞ😒\nSecond line\nThird line\n\nNew paragraph, with a very long line that hopefully will be word wrapped if everything goes according to plan.\n\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH", + "force_wrap": true, + "feed": true +} diff --git a/showbits-thermal-printer/src/documents/text/lib.typ b/showbits-thermal-printer/src/documents/text/lib.typ new file mode 120000 index 0000000..ea61142 --- /dev/null +++ b/showbits-thermal-printer/src/documents/text/lib.typ @@ -0,0 +1 @@ +../lib.typ \ No newline at end of file diff --git a/showbits-thermal-printer/src/documents/text/main.typ b/showbits-thermal-printer/src/documents/text/main.typ new file mode 100644 index 0000000..aed3c9f --- /dev/null +++ b/showbits-thermal-printer/src/documents/text/main.typ @@ -0,0 +1,13 @@ +#import "lib.typ"; +#show: it => lib.init(it) + +#let data = json("data.json") + +#if data.at("force_wrap", default: false) { + show regex("."): it => it + sym.zws + data.text +} else { data.text } + +#if data.at("feed", default: false) { + lib.feed +} diff --git a/showbits-thermal-printer/src/documents/text/mod.rs b/showbits-thermal-printer/src/documents/text/mod.rs new file mode 100644 index 0000000..cb47665 --- /dev/null +++ b/showbits-thermal-printer/src/documents/text/mod.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +use showbits_typst::Typst; + +#[derive(Serialize, Deserialize)] +pub struct Text { + pub text: String, + #[serde(default)] + pub force_wrap: bool, + #[serde(default)] + pub feed: bool, +} + +impl From for Typst { + fn from(value: Text) -> Self { + super::typst_with_lib() + .with_json("/data.json", &value) + .with_main_file(include_str!("main.typ")) + } +} diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs index fa22a70..77e2909 100644 --- a/showbits-thermal-printer/src/drawer.rs +++ b/showbits-thermal-printer/src/drawer.rs @@ -4,6 +4,7 @@ mod cells; mod chat_message; mod egg; mod image; +mod new_typst; mod photo; mod text; mod tictactoe; @@ -16,8 +17,9 @@ use crate::persistent_printer::PersistentPrinter; pub use self::{ backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing, - chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing, photo::PhotoDrawing, - text::TextDrawing, tictactoe::TicTacToeDrawing, typst::TypstDrawing, + chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing, + new_typst::NewTypstDrawing, photo::PhotoDrawing, text::TextDrawing, + tictactoe::TicTacToeDrawing, typst::TypstDrawing, }; pub const FEED: f32 = 96.0; diff --git a/showbits-thermal-printer/src/drawer/new_typst.rs b/showbits-thermal-printer/src/drawer/new_typst.rs new file mode 100644 index 0000000..aa777e3 --- /dev/null +++ b/showbits-thermal-printer/src/drawer/new_typst.rs @@ -0,0 +1,21 @@ +use showbits_typst::Typst; + +use crate::persistent_printer::PersistentPrinter; + +use super::{Context, Drawing}; + +pub struct NewTypstDrawing(pub Typst); + +impl NewTypstDrawing { + pub fn new(typst: impl Into) -> Self { + Self(typst.into()) + } +} + +impl Drawing for NewTypstDrawing { + fn draw(&self, printer: &mut PersistentPrinter, _ctx: &mut Context) -> anyhow::Result<()> { + let image = self.0.render()?; + printer.print_image(&image)?; + Ok(()) + } +} diff --git a/showbits-thermal-printer/src/main.rs b/showbits-thermal-printer/src/main.rs index d5e37a9..da5ef48 100644 --- a/showbits-thermal-printer/src/main.rs +++ b/showbits-thermal-printer/src/main.rs @@ -2,6 +2,7 @@ mod drawer; mod persistent_printer; mod printer; mod server; +mod documents; use std::{path::PathBuf, time::Duration}; diff --git a/showbits-thermal-printer/src/persistent_printer.rs b/showbits-thermal-printer/src/persistent_printer.rs index 4fc0c10..cdfaaa6 100644 --- a/showbits-thermal-printer/src/persistent_printer.rs +++ b/showbits-thermal-printer/src/persistent_printer.rs @@ -44,7 +44,7 @@ impl PersistentPrinter { tree.render(ctx, root, available) } - fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> { + fn print_image_immediately(&mut self, image: &RgbaImage) -> anyhow::Result<()> { let Some(printer) = &mut self.printer else { bail!("no printer found"); }; @@ -60,12 +60,12 @@ impl PersistentPrinter { fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> { println!("Printing image"); - if self.print_image(image).is_ok() { + if self.print_image_immediately(image).is_ok() { return Ok(()); } println!("First attempt failed, reconnecting and retrying"); self.reconnect_printer()?; - self.print_image(image)?; + self.print_image_immediately(image)?; Ok(()) } @@ -86,6 +86,13 @@ impl PersistentPrinter { Ok(()) } + pub fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> { + if self.print_image_robustly(image).is_err() { + self.enqueue_image(image)?; + } + Ok(()) + } + pub fn print_tree( &mut self, tree: &mut Tree, @@ -93,9 +100,7 @@ impl PersistentPrinter { 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)?; - } + self.print_image(&image)?; Ok(()) } diff --git a/showbits-thermal-printer/src/server.rs b/showbits-thermal-printer/src/server.rs index 897c219..602c996 100644 --- a/showbits-thermal-printer/src/server.rs +++ b/showbits-thermal-printer/src/server.rs @@ -13,9 +13,12 @@ use serde::Deserialize; use showbits_common::widgets::DitherAlgorithm; use tokio::{net::TcpListener, sync::mpsc}; -use crate::drawer::{ - CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing, - PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing, +use crate::{ + documents::Text, + drawer::{ + CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing, + NewTypstDrawing, PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing, + }, }; use self::{r#static::get_static_file, statuscode::status_code}; @@ -36,6 +39,7 @@ pub async fn run(tx: mpsc::Sender, addr: String) -> anyhow::Result<()> .route("/text", post(post_text)) .route("/tictactoe", post(post_tictactoe)) .route("/typst", post(post_typst).fallback(get_static_file)) + .route("/test", post(post_test).fallback(get_static_file)) .fallback(get(get_static_file)) .layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB .with_state(Server { tx }); @@ -222,3 +226,12 @@ async fn post_typst(server: State, request: Form) { .send(Command::draw(TypstDrawing(request.0.source))) .await; } + +// /test + +async fn post_test(server: State, request: Form) { + let _ = server + .tx + .send(Command::draw(NewTypstDrawing::new(request.0))) + .await; +}