Remove /photo endpoint
This commit is contained in:
parent
2451bb3d76
commit
d32be913fd
7 changed files with 34 additions and 113 deletions
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"title": "Moon",
|
||||||
|
"caption": "(on the moon)",
|
||||||
"algo": "stucki",
|
"algo": "stucki",
|
||||||
"bright": false,
|
"bright": false,
|
||||||
"seamless": false,
|
"seamless": false,
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,25 @@
|
||||||
|
|
||||||
#let data = json("data.json")
|
#let data = json("data.json")
|
||||||
|
|
||||||
#let dithered = lib.dither(
|
#show: it => if data.seamless {
|
||||||
|
set page(margin: 0pt)
|
||||||
|
it
|
||||||
|
} else { it }
|
||||||
|
|
||||||
|
#if data.title != none {
|
||||||
|
align(center, text(size: 32pt, data.title))
|
||||||
|
}
|
||||||
|
|
||||||
|
#lib.dither(
|
||||||
read("image.png", encoding: none),
|
read("image.png", encoding: none),
|
||||||
bright: data.bright,
|
bright: data.bright,
|
||||||
algorithm: data.algo,
|
algorithm: data.algo,
|
||||||
)
|
)
|
||||||
|
|
||||||
#if data.seamless {
|
#if data.caption != none {
|
||||||
set page(margin: 0pt)
|
align(center, text(size: 32pt, data.caption))
|
||||||
dithered
|
}
|
||||||
if data.feed { lib.feed }
|
|
||||||
} else {
|
#if data.feed {
|
||||||
dithered
|
lib.feed
|
||||||
if data.feed { lib.feed }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ use crate::{
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Data {
|
struct Data {
|
||||||
|
title: Option<String>,
|
||||||
|
caption: Option<String>,
|
||||||
algo: String,
|
algo: String,
|
||||||
bright: bool,
|
bright: bool,
|
||||||
seamless: bool,
|
seamless: bool,
|
||||||
|
|
@ -25,6 +27,8 @@ struct Data {
|
||||||
pub async fn post(server: State<Server>, mut multipart: Multipart) -> somehow::Result<Response> {
|
pub async fn post(server: State<Server>, mut multipart: Multipart) -> somehow::Result<Response> {
|
||||||
let mut image = None;
|
let mut image = None;
|
||||||
let mut data = Data {
|
let mut data = Data {
|
||||||
|
title: None,
|
||||||
|
caption: None,
|
||||||
algo: "stucki".to_string(),
|
algo: "stucki".to_string(),
|
||||||
bright: true,
|
bright: true,
|
||||||
seamless: false,
|
seamless: false,
|
||||||
|
|
@ -38,6 +42,12 @@ pub async fn post(server: State<Server>, mut multipart: Multipart) -> somehow::R
|
||||||
let decoded = image::load_from_memory(&data)?.into_rgba8();
|
let decoded = image::load_from_memory(&data)?.into_rgba8();
|
||||||
image = Some(decoded);
|
image = Some(decoded);
|
||||||
}
|
}
|
||||||
|
Some("title") => {
|
||||||
|
data.title = Some(field.text().await?);
|
||||||
|
}
|
||||||
|
Some("caption") => {
|
||||||
|
data.caption = Some(field.text().await?);
|
||||||
|
}
|
||||||
Some("algo") => {
|
Some("algo") => {
|
||||||
data.algo = field.text().await?;
|
data.algo = field.text().await?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
mod backlog;
|
mod backlog;
|
||||||
mod chat_message;
|
mod chat_message;
|
||||||
mod new_typst;
|
mod new_typst;
|
||||||
mod photo;
|
|
||||||
mod tictactoe;
|
mod tictactoe;
|
||||||
|
|
||||||
use showbits_common::widgets::{FontStuff, HasFontStuff};
|
use showbits_common::widgets::{FontStuff, HasFontStuff};
|
||||||
|
|
@ -11,7 +10,7 @@ use crate::persistent_printer::PersistentPrinter;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
backlog::BacklogDrawing, chat_message::ChatMessageDrawing, new_typst::NewTypstDrawing,
|
backlog::BacklogDrawing, chat_message::ChatMessageDrawing, new_typst::NewTypstDrawing,
|
||||||
photo::PhotoDrawing, tictactoe::TicTacToeDrawing,
|
tictactoe::TicTacToeDrawing,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FEED: f32 = 96.0;
|
pub const FEED: f32 = 96.0;
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use image::{Luma, Pixel, RgbaImage};
|
|
||||||
use showbits_common::{
|
|
||||||
Node, Tree, WidgetExt,
|
|
||||||
color::{BLACK, WHITE},
|
|
||||||
widgets::{Image, Text},
|
|
||||||
};
|
|
||||||
use taffy::{
|
|
||||||
AlignItems, Display, FlexDirection,
|
|
||||||
style_helpers::{length, percent},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::persistent_printer::PersistentPrinter;
|
|
||||||
|
|
||||||
use super::{Context, Drawing, FEED};
|
|
||||||
|
|
||||||
pub struct PhotoDrawing {
|
|
||||||
pub image: RgbaImage,
|
|
||||||
pub title: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drawing for PhotoDrawing {
|
|
||||||
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
|
|
||||||
let mut tree = Tree::<Context>::new(WHITE);
|
|
||||||
|
|
||||||
let mut image = self.image.clone();
|
|
||||||
for pixel in image.pixels_mut() {
|
|
||||||
let [l] = pixel.to_luma().0;
|
|
||||||
let l = l as f32 / 255.0; // Convert to [0, 1]
|
|
||||||
let l = 1.0 - (0.4 * (1.0 - l)); // Lerp to [0.6, 1]
|
|
||||||
let l = (l.clamp(0.0, 1.0) * 255.0) as u8; // Convert back to [0, 255]
|
|
||||||
*pixel = Luma([l]).to_rgba();
|
|
||||||
}
|
|
||||||
|
|
||||||
let image = Image::new(image)
|
|
||||||
.with_dither_palette(&[BLACK, WHITE])
|
|
||||||
.node()
|
|
||||||
.register(&mut tree)?;
|
|
||||||
|
|
||||||
let title = Text::new()
|
|
||||||
.with_metrics(Text::default_metrics().scale(2.0))
|
|
||||||
.and_plain(&self.title)
|
|
||||||
.widget(&mut ctx.font_stuff)
|
|
||||||
.node()
|
|
||||||
.register(&mut tree)?;
|
|
||||||
|
|
||||||
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))
|
|
||||||
.with_gap(length(8.0))
|
|
||||||
.and_child(image)
|
|
||||||
.and_child(title)
|
|
||||||
.register(&mut tree)?;
|
|
||||||
|
|
||||||
printer.print_tree(&mut tree, ctx, root)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,9 +4,7 @@ pub mod statuscode;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Form, Router,
|
Form, Router,
|
||||||
extract::{DefaultBodyLimit, Multipart, State},
|
extract::{DefaultBodyLimit, State},
|
||||||
http::StatusCode,
|
|
||||||
response::{IntoResponse, Redirect, Response},
|
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
@ -14,10 +12,10 @@ use tokio::{net::TcpListener, sync::mpsc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
documents,
|
documents,
|
||||||
drawer::{ChatMessageDrawing, Command, PhotoDrawing, TicTacToeDrawing},
|
drawer::{ChatMessageDrawing, Command, TicTacToeDrawing},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{r#static::get_static_file, statuscode::status_code};
|
use self::r#static::get_static_file;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
|
|
@ -40,7 +38,6 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
|
||||||
"/image",
|
"/image",
|
||||||
post(documents::image::post).fallback(get_static_file),
|
post(documents::image::post).fallback(get_static_file),
|
||||||
)
|
)
|
||||||
.route("/photo", post(post_photo).fallback(get_static_file))
|
|
||||||
.route(
|
.route(
|
||||||
"/text",
|
"/text",
|
||||||
post(documents::text::post).fallback(get_static_file),
|
post(documents::text::post).fallback(get_static_file),
|
||||||
|
|
@ -73,41 +70,6 @@ async fn post_chat_message(server: State<Server>, request: Form<PostChatMessageF
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /photo
|
|
||||||
|
|
||||||
async fn post_photo(server: State<Server>, mut multipart: Multipart) -> somehow::Result<Response> {
|
|
||||||
let mut image = None;
|
|
||||||
let mut title = None;
|
|
||||||
|
|
||||||
while let Some(field) = multipart.next_field().await? {
|
|
||||||
match field.name() {
|
|
||||||
Some("image") => {
|
|
||||||
let data = field.bytes().await?;
|
|
||||||
let decoded = image::load_from_memory(&data)?.into_rgba8();
|
|
||||||
image = Some(decoded);
|
|
||||||
}
|
|
||||||
Some("title") => {
|
|
||||||
title = Some(field.text().await?);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(image) = image else {
|
|
||||||
return Ok(status_code(StatusCode::UNPROCESSABLE_ENTITY));
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(title) = title else {
|
|
||||||
return Ok(status_code(StatusCode::UNPROCESSABLE_ENTITY));
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = server
|
|
||||||
.tx
|
|
||||||
.send(Command::draw(PhotoDrawing { image, title }))
|
|
||||||
.await;
|
|
||||||
Ok(Redirect::to("photo").into_response())
|
|
||||||
}
|
|
||||||
|
|
||||||
// /tictactoe
|
// /tictactoe
|
||||||
|
|
||||||
async fn post_tictactoe(server: State<Server>) {
|
async fn post_tictactoe(server: State<Server>) {
|
||||||
|
|
|
||||||
|
|
@ -137,9 +137,9 @@
|
||||||
canvas.toBlob((blob) => {
|
canvas.toBlob((blob) => {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append("image", blob);
|
form.append("image", blob);
|
||||||
form.append("title", new Date().toLocaleString());
|
form.append("caption", new Date().toLocaleString());
|
||||||
|
|
||||||
fetch("photo", { method: "POST", body: form }).catch((error) => {
|
fetch("image", { method: "POST", body: form }).catch((error) => {
|
||||||
console.error("Error uploading image:", error);
|
console.error("Error uploading image:", error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue