Compare commits
3 commits
cec5d50aa6
...
8b139af199
Author | SHA1 | Date | |
---|---|---|---|
8b139af199 | |||
e912b8a4d1 | |||
4bdcacba41 |
5 changed files with 449 additions and 323 deletions
715
Cargo.lock
generated
715
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -4,6 +4,8 @@ use text::EmbeddedFonts;
|
||||||
use tower_http::{catch_panic::CatchPanicLayer, trace::TraceLayer};
|
use tower_http::{catch_panic::CatchPanicLayer, trace::TraceLayer};
|
||||||
use tracing::Span;
|
use tracing::Span;
|
||||||
|
|
||||||
|
use crate::routes::static_files;
|
||||||
|
|
||||||
mod color;
|
mod color;
|
||||||
mod polygon;
|
mod polygon;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
@ -20,9 +22,9 @@ async fn main() {
|
||||||
fonts: EmbeddedFonts::load(),
|
fonts: EmbeddedFonts::load(),
|
||||||
};
|
};
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.nest("/", routes::static_files::routes())
|
.fallback(static_files::router)
|
||||||
|
.route("/logo", get(routes::logo::png))
|
||||||
.route("/logo.png", get(routes::logo::png))
|
.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()
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
use std::time::Instant;
|
use axum::extract::{Query, State};
|
||||||
|
use cairo::{freetype::Face, Context, FontFace, Format, ImageSurface};
|
||||||
use axum::{
|
|
||||||
extract::{Query, State},
|
|
||||||
routing::get,
|
|
||||||
Router,
|
|
||||||
};
|
|
||||||
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};
|
||||||
|
@ -47,12 +41,6 @@ fn create_image_surface(properties: &ImageProperties) -> ImageSurface {
|
||||||
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) {
|
||||||
|
@ -153,25 +141,3 @@ pub async fn png(
|
||||||
data,
|
data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum_macros::debug_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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,17 +2,14 @@ use axum::{
|
||||||
body::{boxed, Full},
|
body::{boxed, Full},
|
||||||
http::{header, StatusCode, Uri},
|
http::{header, StatusCode, Uri},
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
Router,
|
|
||||||
};
|
};
|
||||||
use rust_embed::{EmbeddedFile, RustEmbed};
|
use rust_embed::{EmbeddedFile, RustEmbed};
|
||||||
|
|
||||||
use crate::SharedState;
|
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
#[folder = "web"]
|
#[folder = "web"]
|
||||||
struct StaticFiles;
|
struct StaticFiles;
|
||||||
|
|
||||||
async fn static_files(uri: Uri) -> impl IntoResponse {
|
pub async fn router(uri: Uri) -> impl IntoResponse {
|
||||||
let path = uri.path().trim_start_matches('/');
|
let path = uri.path().trim_start_matches('/');
|
||||||
|
|
||||||
match StaticFiles::get(path) {
|
match StaticFiles::get(path) {
|
||||||
|
@ -50,7 +47,3 @@ fn not_found() -> Response {
|
||||||
.body(boxed(Full::from("404")))
|
.body(boxed(Full::from("404")))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes() -> Router<SharedState> {
|
|
||||||
Router::new().fallback(static_files)
|
|
||||||
}
|
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<label for="logo_variant">
|
<label for="logo_variant">
|
||||||
Variant
|
Variant
|
||||||
</label>
|
</label>
|
||||||
<select id="logo_variant" value="DarkText">
|
<select id="logo_variant" name="variant" value="DarkText">
|
||||||
<option value="DarkText" selected>dark text</option>
|
<option value="DarkText" selected>dark text</option>
|
||||||
<option value="LightText">light text</option>
|
<option value="LightText">light text</option>
|
||||||
<option value="NoText">no text</option>
|
<option value="NoText">no text</option>
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
Orientation
|
Orientation
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<select id="logo_orientation" value="Landscape">
|
<select id="logo_orientation" name="orientation" value="Landscape">
|
||||||
<option value="Landscape" selected>landscape</option>
|
<option value="Landscape" selected>landscape</option>
|
||||||
<option value="Portrait" selected>portrait</option>
|
<option value="Portrait" selected>portrait</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
Loading…
Reference in a new issue