Chore: commit unstaged changed
This commit is contained in:
parent
9d89154b23
commit
cec5d50aa6
3 changed files with 40 additions and 29 deletions
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
png = "0.11.0"
|
png = "0.11.0"
|
||||||
cairo-rs = { version = "0.17.0", default-features = false, features = ["png", "freetype"] }
|
cairo-rs = { version = "0.17.0", default-features = false, features = ["png", "svg", "freetype"] }
|
||||||
axum = "0.6.10"
|
axum = "0.6.10"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use axum::{http::Request, response::Response, Router};
|
use axum::{http::Request, response::Response, routing::get, Router};
|
||||||
use std::{net::SocketAddr, time::Duration};
|
use std::{net::SocketAddr, time::Duration};
|
||||||
use text::EmbeddedFonts;
|
use text::EmbeddedFonts;
|
||||||
use tower_http::{catch_panic::CatchPanicLayer, trace::TraceLayer};
|
use tower_http::{catch_panic::CatchPanicLayer, trace::TraceLayer};
|
||||||
|
@ -21,7 +21,8 @@ async fn main() {
|
||||||
};
|
};
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.nest("/", routes::static_files::routes())
|
.nest("/", routes::static_files::routes())
|
||||||
.nest("/logo", routes::logo::routes())
|
.route("/logo.png", get(routes::logo::png))
|
||||||
|
.route("/logo.svg", get(routes::logo::svg))
|
||||||
.nest("/favicon.ico", routes::favicon::routes())
|
.nest("/favicon.ico", routes::favicon::routes())
|
||||||
.layer(
|
.layer(
|
||||||
TraceLayer::new_for_http()
|
TraceLayer::new_for_http()
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use cairo::{freetype::Face, Context, FontFace, Format, ImageSurface};
|
use cairo::{freetype::Face, Context, FontFace, Format, ImageSurface, SvgSurface};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{color::Color, polygon, text::DrawableText, SharedState};
|
use crate::{color::Color, polygon, text::DrawableText, SharedState};
|
||||||
|
@ -27,23 +27,32 @@ enum LogoOrientation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
struct ImageProperties {
|
pub struct ImageProperties {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
variant: LogoVariant,
|
variant: LogoVariant,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
orientation: LogoOrientation,
|
orientation: LogoOrientation,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_surface(properties: &ImageProperties) -> ImageSurface {
|
fn get_surface_size(properties: &ImageProperties) -> (i32, i32) {
|
||||||
let (width, height) = match (&properties.variant, &properties.orientation) {
|
match (&properties.variant, &properties.orientation) {
|
||||||
(LogoVariant::NoText, _) => (400, 400),
|
(LogoVariant::NoText, _) => (400, 400),
|
||||||
(_, LogoOrientation::Landscape) => (2127, 591),
|
(_, LogoOrientation::Landscape) => (2127, 591),
|
||||||
(_, LogoOrientation::Portrait) => (1654, 1654),
|
(_, LogoOrientation::Portrait) => (1654, 1654),
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_image_surface(properties: &ImageProperties) -> ImageSurface {
|
||||||
|
let (width, height) = get_surface_size(properties);
|
||||||
ImageSurface::create(Format::ARgb32, width, height).unwrap()
|
ImageSurface::create(Format::ARgb32, width, height).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_svg_surface(properties: &ImageProperties) -> SvgSurface {
|
||||||
|
let (width, height) = get_surface_size(properties);
|
||||||
|
|
||||||
|
SvgSurface::new::<String>(width as f64, height as f64, None).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_logo(context: &Context, properties: &ImageProperties) {
|
fn draw_logo(context: &Context, properties: &ImageProperties) {
|
||||||
let (logo_coordinates, logo_outer_radius, logo_inner_radius) =
|
let (logo_coordinates, logo_outer_radius, logo_inner_radius) =
|
||||||
match (&properties.variant, &properties.orientation) {
|
match (&properties.variant, &properties.orientation) {
|
||||||
|
@ -123,38 +132,21 @@ fn draw_text(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum_macros::debug_handler]
|
#[axum_macros::debug_handler]
|
||||||
async fn handler(
|
pub async fn png(
|
||||||
Query(properties): Query<ImageProperties>,
|
Query(properties): Query<ImageProperties>,
|
||||||
State(state): State<SharedState>,
|
State(state): State<SharedState>,
|
||||||
) -> impl axum::response::IntoResponse {
|
) -> impl axum::response::IntoResponse {
|
||||||
let start = Instant::now();
|
|
||||||
let (font_regular, font_light) = state.fonts.get().await;
|
let (font_regular, font_light) = state.fonts.get().await;
|
||||||
println!("{:?}", start.elapsed());
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
// cannot use await after this, because surface does not implement Send
|
// cannot use await after this, because surface does not implement Send
|
||||||
|
let surface = create_image_surface(&properties);
|
||||||
let surface = create_surface(&properties);
|
|
||||||
let context = Context::new(&surface).unwrap();
|
let context = Context::new(&surface).unwrap();
|
||||||
|
|
||||||
println!("{:?}", (surface.width(), surface.height()));
|
|
||||||
|
|
||||||
println!("{:?}", start.elapsed());
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
draw_logo(&context, &properties);
|
draw_logo(&context, &properties);
|
||||||
println!("{:?}", start.elapsed());
|
|
||||||
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
draw_text(&context, &font_regular, &font_light, &properties);
|
draw_text(&context, &font_regular, &font_light, &properties);
|
||||||
|
|
||||||
println!("{:?}", start.elapsed());
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
let mut data: Vec<u8> = Vec::new();
|
let mut data: Vec<u8> = Vec::new();
|
||||||
surface.write_to_png(&mut data).unwrap();
|
surface.write_to_png(&mut data).unwrap();
|
||||||
println!("{:?}", start.elapsed());
|
|
||||||
|
|
||||||
(
|
(
|
||||||
axum::response::AppendHeaders([(axum::http::header::CONTENT_TYPE, "image/png")]),
|
axum::response::AppendHeaders([(axum::http::header::CONTENT_TYPE, "image/png")]),
|
||||||
|
@ -162,6 +154,24 @@ async fn handler(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes() -> Router<SharedState> {
|
#[axum_macros::debug_handler]
|
||||||
Router::<SharedState>::new().route("/", get(handler))
|
pub async fn svg(
|
||||||
|
Query(properties): Query<ImageProperties>,
|
||||||
|
State(state): State<SharedState>,
|
||||||
|
) -> impl axum::response::IntoResponse {
|
||||||
|
let (font_regular, font_light) = state.fonts.get().await;
|
||||||
|
|
||||||
|
// cannot use await after this, because surface does not implement Send
|
||||||
|
let surface = create_svg_surface(&properties);
|
||||||
|
let context = Context::new(&surface).unwrap();
|
||||||
|
|
||||||
|
draw_logo(&context, &properties);
|
||||||
|
draw_text(&context, &font_regular, &font_light, &properties);
|
||||||
|
|
||||||
|
let mut data: Vec<u8> = Vec::new();
|
||||||
|
surface.write_to_png(&mut data).unwrap();
|
||||||
|
(
|
||||||
|
axum::response::AppendHeaders([(axum::http::header::CONTENT_TYPE, "image/png")]),
|
||||||
|
data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue