Use new typst rendering in /test endpoint
This commit is contained in:
parent
8526566f39
commit
428b825e43
15 changed files with 128 additions and 14 deletions
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"[html]": {
|
"[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
}
|
"[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||||
|
"tinymist.fontPaths": ["showbits-assets/data"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2514,6 +2514,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"showbits-assets",
|
"showbits-assets",
|
||||||
"showbits-common",
|
"showbits-common",
|
||||||
|
"showbits-typst",
|
||||||
"taffy",
|
"taffy",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ rust-embed = "8.5.0"
|
||||||
serde = { version = "1.0.218", features = ["derive"] }
|
serde = { version = "1.0.218", features = ["derive"] }
|
||||||
showbits-assets.path = "./showbits-assets"
|
showbits-assets.path = "./showbits-assets"
|
||||||
showbits-common.path = "./showbits-common"
|
showbits-common.path = "./showbits-common"
|
||||||
|
showbits-typst.path = "./showbits-typst"
|
||||||
tokio = "1.43.0"
|
tokio = "1.43.0"
|
||||||
typst = "0.13.0"
|
typst = "0.13.0"
|
||||||
typst-assets = { version = "0.13.0", features = ["fonts"] }
|
typst-assets = { version = "0.13.0", features = ["fonts"] }
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ rust-embed = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
showbits-assets = { workspace = true }
|
showbits-assets = { workspace = true }
|
||||||
showbits-common = { workspace = true }
|
showbits-common = { workspace = true }
|
||||||
|
showbits-typst = { workspace = true }
|
||||||
taffy = { workspace = true }
|
taffy = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
|
|
||||||
|
|
|
||||||
9
showbits-thermal-printer/src/documents.rs
Normal file
9
showbits-thermal-printer/src/documents.rs
Normal file
|
|
@ -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"))
|
||||||
|
}
|
||||||
21
showbits-thermal-printer/src/documents/lib.typ
Normal file
21
showbits-thermal-printer/src/documents/lib.typ
Normal file
|
|
@ -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)
|
||||||
5
showbits-thermal-printer/src/documents/text/data.json
Normal file
5
showbits-thermal-printer/src/documents/text/data.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
1
showbits-thermal-printer/src/documents/text/lib.typ
Symbolic link
1
showbits-thermal-printer/src/documents/text/lib.typ
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../lib.typ
|
||||||
13
showbits-thermal-printer/src/documents/text/main.typ
Normal file
13
showbits-thermal-printer/src/documents/text/main.typ
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
19
showbits-thermal-printer/src/documents/text/mod.rs
Normal file
19
showbits-thermal-printer/src/documents/text/mod.rs
Normal file
|
|
@ -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<Text> for Typst {
|
||||||
|
fn from(value: Text) -> Self {
|
||||||
|
super::typst_with_lib()
|
||||||
|
.with_json("/data.json", &value)
|
||||||
|
.with_main_file(include_str!("main.typ"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ mod cells;
|
||||||
mod chat_message;
|
mod chat_message;
|
||||||
mod egg;
|
mod egg;
|
||||||
mod image;
|
mod image;
|
||||||
|
mod new_typst;
|
||||||
mod photo;
|
mod photo;
|
||||||
mod text;
|
mod text;
|
||||||
mod tictactoe;
|
mod tictactoe;
|
||||||
|
|
@ -16,8 +17,9 @@ use crate::persistent_printer::PersistentPrinter;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing,
|
backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing,
|
||||||
chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing, photo::PhotoDrawing,
|
chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing,
|
||||||
text::TextDrawing, tictactoe::TicTacToeDrawing, typst::TypstDrawing,
|
new_typst::NewTypstDrawing, photo::PhotoDrawing, text::TextDrawing,
|
||||||
|
tictactoe::TicTacToeDrawing, typst::TypstDrawing,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FEED: f32 = 96.0;
|
pub const FEED: f32 = 96.0;
|
||||||
|
|
|
||||||
21
showbits-thermal-printer/src/drawer/new_typst.rs
Normal file
21
showbits-thermal-printer/src/drawer/new_typst.rs
Normal file
|
|
@ -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<Typst>) -> 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ mod drawer;
|
||||||
mod persistent_printer;
|
mod persistent_printer;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod server;
|
mod server;
|
||||||
|
mod documents;
|
||||||
|
|
||||||
use std::{path::PathBuf, time::Duration};
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ impl PersistentPrinter {
|
||||||
tree.render(ctx, root, available)
|
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 {
|
let Some(printer) = &mut self.printer else {
|
||||||
bail!("no printer found");
|
bail!("no printer found");
|
||||||
};
|
};
|
||||||
|
|
@ -60,12 +60,12 @@ impl PersistentPrinter {
|
||||||
|
|
||||||
fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
|
||||||
println!("Printing image");
|
println!("Printing image");
|
||||||
if self.print_image(image).is_ok() {
|
if self.print_image_immediately(image).is_ok() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
println!("First attempt failed, reconnecting and retrying");
|
println!("First attempt failed, reconnecting and retrying");
|
||||||
self.reconnect_printer()?;
|
self.reconnect_printer()?;
|
||||||
self.print_image(image)?;
|
self.print_image_immediately(image)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +86,13 @@ impl PersistentPrinter {
|
||||||
Ok(())
|
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<C>(
|
pub fn print_tree<C>(
|
||||||
&mut self,
|
&mut self,
|
||||||
tree: &mut Tree<C>,
|
tree: &mut Tree<C>,
|
||||||
|
|
@ -93,9 +100,7 @@ impl PersistentPrinter {
|
||||||
root: NodeId,
|
root: NodeId,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let image = Self::render_tree_to_image(tree, ctx, root)?;
|
let image = Self::render_tree_to_image(tree, ctx, root)?;
|
||||||
if self.print_image_robustly(&image).is_err() {
|
self.print_image(&image)?;
|
||||||
self.enqueue_image(&image)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,12 @@ use serde::Deserialize;
|
||||||
use showbits_common::widgets::DitherAlgorithm;
|
use showbits_common::widgets::DitherAlgorithm;
|
||||||
use tokio::{net::TcpListener, sync::mpsc};
|
use tokio::{net::TcpListener, sync::mpsc};
|
||||||
|
|
||||||
use crate::drawer::{
|
use crate::{
|
||||||
CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing,
|
documents::Text,
|
||||||
PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing,
|
drawer::{
|
||||||
|
CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing,
|
||||||
|
NewTypstDrawing, PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{r#static::get_static_file, statuscode::status_code};
|
use self::{r#static::get_static_file, statuscode::status_code};
|
||||||
|
|
@ -36,6 +39,7 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
|
||||||
.route("/text", post(post_text))
|
.route("/text", post(post_text))
|
||||||
.route("/tictactoe", post(post_tictactoe))
|
.route("/tictactoe", post(post_tictactoe))
|
||||||
.route("/typst", post(post_typst).fallback(get_static_file))
|
.route("/typst", post(post_typst).fallback(get_static_file))
|
||||||
|
.route("/test", post(post_test).fallback(get_static_file))
|
||||||
.fallback(get(get_static_file))
|
.fallback(get(get_static_file))
|
||||||
.layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB
|
.layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB
|
||||||
.with_state(Server { tx });
|
.with_state(Server { tx });
|
||||||
|
|
@ -222,3 +226,12 @@ async fn post_typst(server: State<Server>, request: Form<PostTypstForm>) {
|
||||||
.send(Command::draw(TypstDrawing(request.0.source)))
|
.send(Command::draw(TypstDrawing(request.0.source)))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /test
|
||||||
|
|
||||||
|
async fn post_test(server: State<Server>, request: Form<Text>) {
|
||||||
|
let _ = server
|
||||||
|
.tx
|
||||||
|
.send(Command::draw(NewTypstDrawing::new(request.0)))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue