add palette selection; make image request extractor

This commit is contained in:
saji 2024-07-30 08:53:47 -05:00
parent c7e57f3d3b
commit 599fb09503
2 changed files with 35 additions and 25 deletions

View file

@ -1,11 +1,12 @@
use crate::display::EInkPanel; use crate::display::EInkPanel;
use crate::imageproc::{DitherMethod, DitherPalette, EInkImage}; use crate::imageproc::{DitherMethod, DitherPalette, EInkImage};
use axum::extract::Multipart; use axum::async_trait;
use axum::extract::{FromRequest, Multipart, State};
use axum::http::{header, StatusCode}; use axum::http::{header, StatusCode};
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::{extract::State, response::Response, routing::post, Router}; use axum::{response::Response, routing::post, Router};
use image::{ImageReader, RgbImage}; use image::{ImageReader, RgbImage};
use std::io::{BufWriter, Cursor}; use std::io::Cursor;
use std::str; use std::str;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@ -98,8 +99,15 @@ struct ImageRequest {
palette: DitherPalette, palette: DitherPalette,
} }
impl ImageRequest { #[async_trait]
async fn from_multipart(mut parts: Multipart) -> Result<Self, AppError> { impl<S> FromRequest<S> for ImageRequest
where
S: Send + Sync,
{
type Rejection = AppError;
async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
let mut parts = Multipart::from_request(req, state).await?;
let mut img = None; let mut img = None;
let mut palette = None; let mut palette = None;
let mut dither_method = None; let mut dither_method = None;
@ -141,13 +149,12 @@ impl ImageRequest {
#[instrument(skip(ctx))] #[instrument(skip(ctx))]
async fn set_image( async fn set_image(
State(ctx): State<Context>, State(ctx): State<Context>,
parts: Multipart, img_req: ImageRequest,
) -> Result<impl IntoResponse, AppError> { ) -> Result<impl IntoResponse, AppError> {
let call = ImageRequest::from_multipart(parts).await?; let mut buf = EInkImage::new(img_req.palette.value().to_vec());
let mut buf = EInkImage::new(call.palette.value().to_vec());
{ {
let mut dither = call.dither_method.get_ditherer(); let mut dither = img_req.dither_method.get_ditherer();
dither.dither(&call.image, &mut buf); dither.dither(&img_req.image, &mut buf);
} }
let cmd = DisplaySetCommand { img: Box::new(buf) }; let cmd = DisplaySetCommand { img: Box::new(buf) };
ctx.display_channel ctx.display_channel
@ -158,12 +165,11 @@ async fn set_image(
/// generates a dithered image based on the given image and the dithering parameters. /// generates a dithered image based on the given image and the dithering parameters.
/// Can be used to see how the dithering and palette choices affect the result. /// Can be used to see how the dithering and palette choices affect the result.
async fn preview_image(parts: Multipart) -> Result<impl IntoResponse, AppError> { async fn preview_image(img_req: ImageRequest) -> Result<impl IntoResponse, AppError> {
let call = ImageRequest::from_multipart(parts).await?; let mut buf = EInkImage::new(img_req.palette.value().to_vec());
let mut buf = EInkImage::new(call.palette.value().to_vec());
{ {
let mut dither = call.dither_method.get_ditherer(); let mut dither = img_req.dither_method.get_ditherer();
dither.dither(&call.image, &mut buf); dither.dither(&img_req.image, &mut buf);
} }
// Convert buf into a png image. // Convert buf into a png image.
let img = buf.into_rgbimage(); let img = buf.into_rgbimage();

View file

@ -21,8 +21,8 @@ const DISPLAY_PALETTE: [Srgb; 7] = [
]; ];
const SIMPLE_PALETTE: [Srgb; 7] = [ const SIMPLE_PALETTE: [Srgb; 7] = [
Srgb::new(0.0,0.0,0.0), // Black Srgb::new(0.0, 0.0, 0.0), // Black
Srgb::new(1.0,1.0,1.0), // White Srgb::new(1.0, 1.0, 1.0), // White
Srgb::new(0.0, 1.0, 0.0), // Green Srgb::new(0.0, 1.0, 0.0), // Green
Srgb::new(0.0, 0.0, 1.0), // Blue Srgb::new(0.0, 0.0, 1.0), // Blue
Srgb::new(1.0, 0.0, 0.0), // Red Srgb::new(1.0, 0.0, 0.0), // Red
@ -37,10 +37,11 @@ pub enum DitherPalette {
} }
impl DitherPalette { impl DitherPalette {
pub fn value(&self) -> &[Srgb] { #[must_use]
pub const fn value(&self) -> &[Srgb] {
match self { match self {
Self::Default => &DISPLAY_PALETTE, Self::Default => &DISPLAY_PALETTE,
Self::Simple => &DISPLAY_PALETTE, // FIXME: use simple pallete based on binary. Self::Simple => &SIMPLE_PALETTE, // FIXME: use simple pallete based on binary.
} }
} }
} }
@ -94,7 +95,10 @@ impl EInkImage {
pub fn into_rgbimage(&self) -> RgbImage { pub fn into_rgbimage(&self) -> RgbImage {
RgbImage::from_fn(self.buf.width(), self.buf.height(), |x, y| { RgbImage::from_fn(self.buf.width(), self.buf.height(), |x, y| {
let idx = self.buf.get_pixel(x, y).0[0]; let idx = self.buf.get_pixel(x, y).0[0];
let disp_color = self.palette.get(idx as usize).unwrap(); let disp_color = self
.palette
.get(idx as usize)
.expect("Palette will never be out of bounds");
let arr: [u8; 3] = disp_color.into_format().into(); let arr: [u8; 3] = disp_color.into_format().into();
imgRgb(arr) imgRgb(arr)
}) })
@ -174,7 +178,7 @@ fn compute_error_adjusted_color(orig: &Lab, err: &Lab, weight: f32) -> Lab {
/// ``DiffusionPoint`` is part of the diffusion matrix, represented by a shift in x and y and an error /// ``DiffusionPoint`` is part of the diffusion matrix, represented by a shift in x and y and an error
/// scaling factor. /// scaling factor.
#[derive(Debug)] #[derive(Debug)]
struct DiffusionPoint { pub struct DiffusionPoint {
xshift: i32, xshift: i32,
yshift: i32, yshift: i32,
scale: f32, scale: f32,