.editorconfig
+14
-0
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..3894928
@@ -0,0 +1,14 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.rs]
indent_style = space
indent_size = 4
max_line_length = 120
[*.toml]
indent_style = space
indent_size = 2
.gitignore
+1
-0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
@@ -0,0 +1 @@
/target
Cargo.lock
+3673
-0
Large diff (3673 lines changed) - not displayed
Cargo.toml
+10
-0
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..ee16a38
@@ -0,0 +1,10 @@
[package]
name = "receipt-printer"
version = "0.1.0"
edition = "2024"
[dependencies]
escpos = { version = "0.17.0", features = ["graphics"] }
typst = "0.14.2"
typst-as-lib = { version = "0.15.4", features = ["typst-kit-fonts"] }
typst-render = "0.14.2"
receipt.typ
+14
-0
diff --git a/receipt.typ b/receipt.typ
new file mode 100644
index 0000000..c5a3cb8
@@ -0,0 +1,14 @@
#set page(
width: 7cm,
height: auto,
margin: (y: 0.1cm, x: 0.05cm),
fill: none,
)
#set text(font: "Times New Roman")
#show title: set align(center)
#title[Mårtens Split App]
#set par(justify: true)
#lorem(40)
src/main.rs
+86
-0
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..2d11b92
@@ -0,0 +1,86 @@
use std::{env::args, time::Duration};
use escpos::{
driver::NetworkDriver,
printer::Printer,
utils::{BitImageOption, BitImageSize, Protocol},
};
use typst::layout::PagedDocument;
use typst_as_lib::{TypstEngine, typst_kit_options::TypstKitFontOptions};
fn main() {
let args: Vec<_> = args().skip(1).collect();
if args.len() != 2 {
println!("Please provide the printer connection string and .typ template as arguments");
return;
};
let Some((printer_host, printer_port)) = args[0]
.split_once(':')
.map(|(a, b)| b.parse::<u16>().ok().map(|b| (a, b)))
.flatten()
else {
println!("Printer connection string must be on format `host:port`");
return;
};
let template_path = &args[1];
let engine = TypstEngine::builder()
.with_file_system_resolver(".")
.search_fonts_with(TypstKitFontOptions::new().include_system_fonts(true))
.build();
println!("Compiling document...");
let document: PagedDocument = match engine.compile(template_path.as_ref()).output {
Ok(document) => document,
Err(error) => {
println!("Failed to compile with message: {error}");
return;
}
};
let width_pixel = 72*8;
let width_cm = 7.2;
let width_pt = width_cm / 0.03527;
let pixel_per_pt = width_pixel as f32 / width_pt;
println!("Rendering document...");
let pixmap = typst_render::render(&document.pages[0], pixel_per_pt);
println!("Pixel size: {}x{}", pixmap.width(), pixmap.height());
let png = match pixmap.encode_png() {
Ok(png) => png,
Err(error) => {
println!("Could not encode image to PNG: {error}");
return;
}
};
println!("Connecting to printer...");
let driver = match NetworkDriver::open(printer_host, printer_port, Some(Duration::from_secs(5)))
{
Ok(driver) => driver,
Err(error) => {
println!("Error connecting to printer: {error}");
return;
}
};
println!("Initializing printer...");
let mut printer = Printer::new(driver, Protocol::default(), None);
if let Err(error) = printer.init() {
println!("Error initializing printer: {error}");
return;
}
println!("Sending image to printer...");
if let Err(error) = printer.bit_image_from_bytes_option(
&png,
BitImageOption::new(Some(width_pixel), None, BitImageSize::Normal).unwrap(),
) {
println!("Error when printing document: {error}");
return;
}
println!("Printing...");
if let Err(error) = printer.print_cut() {
println!("Error when printing: {error}");
return;
}
println!("Done!");
}