Add option to export original images
This commit is contained in:
parent
c8fb228a24
commit
dad0f282c6
5 changed files with 51 additions and 20 deletions
|
|
@ -1,14 +1,15 @@
|
|||
#!/usr/bin/env fish
|
||||
|
||||
argparse h/help p/print r/release -- $argv
|
||||
argparse h/help p/print o/originals r/release -- $argv
|
||||
and not set -ql _flag_help
|
||||
or begin
|
||||
echo "Usage:" (status filename) "[OPTIONS]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Show this help"
|
||||
echo " -p, --print Attach to printer at /dev/usb/lp0"
|
||||
echo " -r, --release Use 'cargo run --release'"
|
||||
echo " -h, --help Show this help"
|
||||
echo " -p, --print Attach to printer at /dev/usb/lp0"
|
||||
echo " -o, --originals Export original images"
|
||||
echo " -r, --release Use 'cargo run --release'"
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -22,6 +23,11 @@ if set -ql _flag_print
|
|||
set arg_print -p /dev/usb/lp0
|
||||
end
|
||||
|
||||
set -l arg_originals
|
||||
if set -ql _flag_originals
|
||||
set arg_originals -o target/originals
|
||||
end
|
||||
|
||||
cargo run $arg_release \
|
||||
--package showbits-thermal-printer \
|
||||
-- target/queue -e target/image.png $arg_print
|
||||
-- target/queue -e target/image.png $arg_print $arg_originals
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Description=Showbits Thermal Printer
|
|||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/home/bondrucker/showbits-thermal-printer queue -a 0.0.0.0:8001 -p /dev/usb/lp0
|
||||
# ExecStart=/home/bondrucker/showbits-thermal-printer queue -a 0.0.0.0:8001 -p /dev/usb/lp0 -o originals
|
||||
Restart=on-failure
|
||||
|
||||
User=bondrucker
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::Cursor;
|
||||
use std::{fs, io::Cursor};
|
||||
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use axum::{
|
||||
|
|
@ -10,6 +10,7 @@ use image::{
|
|||
DynamicImage, EncodableLayout, ImageDecoder, ImageFormat, ImageReader, Luma, Pixel, RgbaImage,
|
||||
imageops,
|
||||
};
|
||||
use jiff::Timestamp;
|
||||
use mark::dither::{AlgoFloydSteinberg, AlgoStucki, Algorithm, DiffEuclid, Palette};
|
||||
use palette::LinSrgb;
|
||||
use serde::Serialize;
|
||||
|
|
@ -101,17 +102,7 @@ pub async fn post(server: State<Server>, mut multipart: Multipart) -> somehow::R
|
|||
while let Some(field) = multipart.next_field().await? {
|
||||
match field.name() {
|
||||
Some("image") => {
|
||||
let data = field.bytes().await?;
|
||||
|
||||
// https://github.com/image-rs/image/issues/2392#issuecomment-2547393362
|
||||
let mut decoder = ImageReader::new(Cursor::new(data.as_bytes()))
|
||||
.with_guessed_format()?
|
||||
.into_decoder()?;
|
||||
let orientation = decoder.orientation()?;
|
||||
let mut decoded = DynamicImage::from_decoder(decoder)?;
|
||||
decoded.apply_orientation(orientation);
|
||||
|
||||
image = Some(decoded.to_rgba8());
|
||||
image = Some(field.bytes().await?);
|
||||
}
|
||||
Some("title") => {
|
||||
data.title = Some(field.text().await?).filter(|it| !it.is_empty());
|
||||
|
|
@ -139,10 +130,31 @@ pub async fn post(server: State<Server>, mut multipart: Multipart) -> somehow::R
|
|||
return Ok(status_code(StatusCode::UNPROCESSABLE_ENTITY));
|
||||
};
|
||||
|
||||
// Export original image if requested
|
||||
if let Some(dir) = &server.originals {
|
||||
fs::create_dir_all(dir)?;
|
||||
let path = dir.join(Timestamp::now().as_millisecond().to_string());
|
||||
fs::write(path, &image)?;
|
||||
}
|
||||
|
||||
// Decode image data
|
||||
let image = {
|
||||
// https://github.com/image-rs/image/issues/2392#issuecomment-2547393362
|
||||
let mut decoder = ImageReader::new(Cursor::new(image.as_bytes()))
|
||||
.with_guessed_format()?
|
||||
.into_decoder()?;
|
||||
let orientation = decoder.orientation()?;
|
||||
let mut decoded = DynamicImage::from_decoder(decoder)?;
|
||||
decoded.apply_orientation(orientation);
|
||||
decoded.to_rgba8()
|
||||
};
|
||||
|
||||
// Dither image
|
||||
let max_width = Some(384);
|
||||
let max_height = Some(1024);
|
||||
let image = dither(image, max_width, max_height, bright, &algo).map_err(somehow::Error)?;
|
||||
|
||||
// Encode dithered image for typst
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
image
|
||||
.write_to(&mut Cursor::new(&mut bytes), ImageFormat::Png)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ struct Args {
|
|||
/// Export an image of whatever is printed here.
|
||||
#[arg(long, short)]
|
||||
export: Option<PathBuf>,
|
||||
|
||||
/// Export the original images printed by the image document, before
|
||||
/// dithering or other manipulation.
|
||||
#[arg(long, short)]
|
||||
originals: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
|
|
@ -44,7 +49,7 @@ fn main() -> anyhow::Result<()> {
|
|||
let mut drawer = Drawer::new(rx, printer);
|
||||
|
||||
let runtime = Runtime::new()?;
|
||||
runtime.spawn(server::run(tx.clone(), args.address));
|
||||
runtime.spawn(server::run(tx.clone(), args.address, args.originals));
|
||||
runtime.spawn(async move {
|
||||
loop {
|
||||
let _ = tx.send(Command::Backlog).await;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ pub mod somehow;
|
|||
mod r#static;
|
||||
pub mod statuscode;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use axum::{
|
||||
Router,
|
||||
extract::DefaultBodyLimit,
|
||||
|
|
@ -18,6 +20,7 @@ use crate::{documents, drawer::Command};
|
|||
#[derive(Clone)]
|
||||
pub struct Server {
|
||||
tx: mpsc::Sender<Command>,
|
||||
pub originals: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
|
|
@ -28,7 +31,11 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()> {
|
||||
pub async fn run(
|
||||
tx: mpsc::Sender<Command>,
|
||||
addr: String,
|
||||
originals: Option<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
let app = Router::new()
|
||||
// Files
|
||||
.route("/", get(r#static::get_index))
|
||||
|
|
@ -47,7 +54,7 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
|
|||
.route("/api/xkcd", post(documents::xkcd::post))
|
||||
// Rest
|
||||
.layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB
|
||||
.with_state(Server { tx });
|
||||
.with_state(Server { tx, originals });
|
||||
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
axum::serve(listener, app).await?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue