add palette selection; make image request extractor
This commit is contained in:
parent
c7e57f3d3b
commit
599fb09503
36
src/api.rs
36
src/api.rs
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue