Compare commits
No commits in common. "ce6c45e2857050315a3aa6534a39495ed8a8ab32" and "75e569182423fe0a87d671166a0620520cc473b2" have entirely different histories.
ce6c45e285
...
75e5691824
10 changed files with 65 additions and 84 deletions
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
14
src/color.rs
14
src/color.rs
|
@ -60,18 +60,6 @@ where
|
|||
Ok(res.unwrap())
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn from_hex(hex: &str) -> Self {
|
||||
serde_json::from_str(&format!("\"{hex}\"")).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Color {
|
||||
fn from(value: &str) -> Self {
|
||||
Color::from_hex(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_serialize_color() {
|
||||
|
@ -92,7 +80,7 @@ fn test_deserialize_color() {
|
|||
|
||||
let deserialized_color: Color = serde_json::from_str(color).unwrap();
|
||||
assert_eq!(deserialized_color.r, 10);
|
||||
assert_eq!(deserialized_color.g, 20);
|
||||
assert_eq!(deserialized_color.g, 20);
|
||||
assert_eq!(deserialized_color.b, 30);
|
||||
|
||||
assert!(serde_json::from_str::<Color>("\"000000\"").is_err());
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#![feature(const_trait_impl)]
|
||||
#![feature(const_convert)]
|
||||
|
||||
use axum::Router;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
use cairo::Context;
|
||||
use rand::{rngs::ThreadRng, Rng};
|
||||
|
||||
use crate::color::Color;
|
||||
|
||||
static COLORS: [(&str, &str); 3] = [
|
||||
("#F4A263", "#E87052"),
|
||||
("#E0DA48", "#969A1D"),
|
||||
("#309E8F", "#2F3F52"),
|
||||
];
|
||||
|
||||
fn calculate_polygon_corners(
|
||||
center: (f64, f64),
|
||||
num_sides: i32,
|
||||
radius: f64,
|
||||
side_length: f64,
|
||||
rotation_angle_degrees: f64,
|
||||
) -> Vec<(f64, f64)> {
|
||||
// no idea how this code works, it was written by ChatGPT
|
||||
let mut corners = Vec::new();
|
||||
let rotation_angle = rotation_angle_degrees.to_radians();
|
||||
let angle = std::f64::consts::PI / (num_sides as f64);
|
||||
let radius = side_length / (2.0 * angle.cos());
|
||||
|
||||
for i in 0..num_sides {
|
||||
let vertex_angle = angle * (2.0 * i as f64 + 1.0 - num_sides as f64) + rotation_angle;
|
||||
|
@ -30,18 +23,41 @@ fn calculate_polygon_corners(
|
|||
corners
|
||||
}
|
||||
|
||||
fn set_color(color: Color, context: &Context) {
|
||||
context.set_source_rgb(
|
||||
color.r as f64 / 255.0,
|
||||
color.g as f64 / 255.0,
|
||||
color.b as f64 / 255.0,
|
||||
);
|
||||
fn set_color_i8((r, g, b): (u8, u8, u8), context: &Context) {
|
||||
context.set_source_rgb(r as f64 / 255.0, g as f64 / 255.0, b as f64 / 255.0);
|
||||
}
|
||||
|
||||
fn generate_colors(rng: &mut ThreadRng) -> (Color, Color) {
|
||||
let color_num = rng.gen_range(0..COLORS.len());
|
||||
let (c1, c2) = COLORS[color_num];
|
||||
(Color::from_hex(c1), Color::from_hex(c2))
|
||||
fn generate_color(
|
||||
rng: &mut ThreadRng,
|
||||
dark_mode: bool,
|
||||
unlike: Option<(u8, u8, u8)>,
|
||||
) -> (u8, u8, u8) {
|
||||
let criteria = |(r, g, b): (u8, u8, u8)| {
|
||||
let r = r as u16;
|
||||
let g = g as u16;
|
||||
let b = b as u16;
|
||||
if dark_mode && (r + g + b) < 300 {
|
||||
return false;
|
||||
} else if !dark_mode && (r + g + b) > 500 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some((r1, g1, b1)) = unlike {
|
||||
if (r.abs_diff(r1 as u16) + g.abs_diff(g1 as u16) + b.abs_diff(b1 as u16)) < 200 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
let mut color = rng.gen();
|
||||
|
||||
while !criteria(color) {
|
||||
color = rng.gen();
|
||||
}
|
||||
|
||||
color
|
||||
}
|
||||
|
||||
pub fn draw_polygon(
|
||||
|
@ -49,10 +65,11 @@ pub fn draw_polygon(
|
|||
side_length: f64,
|
||||
num_sides: i32,
|
||||
context: &Context,
|
||||
dark_mode: bool,
|
||||
) -> Result<(), cairo::Error> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let (c1, _) = generate_colors(&mut rng);
|
||||
set_color(c1, context);
|
||||
let c1 = generate_color(&mut rng, dark_mode, None);
|
||||
set_color_i8(c1, context);
|
||||
context.new_path();
|
||||
|
||||
let corners = calculate_polygon_corners(center, num_sides, side_length, 30.0);
|
||||
|
@ -72,10 +89,11 @@ pub fn draw_segmented_polygon(
|
|||
side_length: f64,
|
||||
num_sides: i32,
|
||||
context: &Context,
|
||||
dark_mode: bool,
|
||||
) -> Result<(), cairo::Error> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let (c1, c2) = generate_colors(&mut rng);
|
||||
set_color(c1, context);
|
||||
let c1 = generate_color(&mut rng, dark_mode, None);
|
||||
set_color_i8(c1, context);
|
||||
context.new_path();
|
||||
|
||||
let corners = calculate_polygon_corners(center, num_sides, side_length, 30.0);
|
||||
|
@ -94,7 +112,8 @@ pub fn draw_segmented_polygon(
|
|||
context.close_path();
|
||||
context.fill()?;
|
||||
|
||||
set_color(c2, context);
|
||||
let c2 = generate_color(&mut rng, dark_mode, Some(c1));
|
||||
set_color_i8(c2, context);
|
||||
context.new_path();
|
||||
// draw other side
|
||||
for i in to_corner..(from_corner + 1 + 6) {
|
||||
|
@ -110,27 +129,28 @@ pub fn draw_segmented_polygon(
|
|||
|
||||
pub fn draw_polygon_of_segmented_polygons(
|
||||
center: (f64, f64),
|
||||
radius: f64,
|
||||
inner_radius: f64,
|
||||
side_length: f64,
|
||||
num_sides: i32,
|
||||
context: &Context,
|
||||
dark_mode: bool,
|
||||
) -> Result<(), cairo::Error> {
|
||||
let corners = calculate_polygon_corners(center, num_sides, radius, 0.0);
|
||||
let corners = calculate_polygon_corners(center, num_sides, side_length, 0.0);
|
||||
for corner in corners {
|
||||
draw_segmented_polygon(corner, inner_radius, num_sides, &context)?;
|
||||
draw_segmented_polygon(corner, side_length * 0.4, num_sides, &context, dark_mode)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw_polygon_of_polygons(
|
||||
center: (f64, f64),
|
||||
radius: f64,
|
||||
side_length: f64,
|
||||
num_sides: i32,
|
||||
context: &Context,
|
||||
dark_mode: bool,
|
||||
) -> Result<(), cairo::Error> {
|
||||
let corners = calculate_polygon_corners(center, num_sides, radius, 0.0);
|
||||
let corners = calculate_polygon_corners(center, num_sides, side_length, 0.0);
|
||||
for corner in corners {
|
||||
draw_polygon(corner, radius * 0.4, num_sides, &context)?;
|
||||
draw_polygon(corner, side_length * 0.4, num_sides, &context, dark_mode)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ async fn handler() -> impl axum::response::IntoResponse {
|
|||
context.set_source_rgba(0.0, 0.0, 0.0, 0.0);
|
||||
context.fill().unwrap();
|
||||
|
||||
polygon::draw_polygon_of_polygons((50.0, 50.0), 65.0, 6, &context).unwrap();
|
||||
polygon::draw_polygon_of_polygons((50.0, 50.0), 65.0, 6, &context, false).unwrap();
|
||||
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
surface.write_to_png(&mut data).unwrap();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use axum::{extract::Query, routing::get, Router};
|
||||
use cairo::{Context, Format, ImageSurface};
|
||||
use rust_embed::RustEmbed;
|
||||
use serde::{de, Deserialize};
|
||||
|
||||
use crate::{color::Color, polygon, SharedState};
|
||||
|
@ -30,33 +29,11 @@ struct ImageProperties {
|
|||
#[serde(default = "default_as_false")]
|
||||
#[serde(deserialize_with = "deserialize_bool")]
|
||||
dark_mode: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(deserialize_with = "deserialize_bool")]
|
||||
text: bool,
|
||||
background_color: Option<Color>,
|
||||
}
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "images"]
|
||||
struct ImageFiles;
|
||||
|
||||
fn get_surface_and_logo_coordiates(properties: &ImageProperties) -> (ImageSurface, (f64, f64)) {
|
||||
if properties.text {
|
||||
let image = ImageFiles::get("Makerlab.png").unwrap();
|
||||
(
|
||||
ImageSurface::create_from_png(&mut image.data.as_ref()).unwrap(),
|
||||
(604.0, 432.0),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
ImageSurface::create(Format::ARgb32, 400, 400).unwrap(),
|
||||
(200.0, 200.0),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn handler(Query(properties): Query<ImageProperties>) -> impl axum::response::IntoResponse {
|
||||
let (surface, logo_coordinates) = get_surface_and_logo_coordiates(&properties);
|
||||
let surface = ImageSurface::create(Format::ARgb32, 400, 400).unwrap();
|
||||
let context = Context::new(&surface).unwrap();
|
||||
|
||||
if let Some(c) = properties.background_color {
|
||||
|
@ -67,8 +44,14 @@ async fn handler(Query(properties): Query<ImageProperties>) -> impl axum::respon
|
|||
|
||||
context.paint().unwrap();
|
||||
|
||||
polygon::draw_polygon_of_segmented_polygons(logo_coordinates, 148.0, 67.0, 6, &context)
|
||||
.unwrap();
|
||||
polygon::draw_polygon_of_segmented_polygons(
|
||||
(200.0, 200.0),
|
||||
200.0,
|
||||
6,
|
||||
&context,
|
||||
properties.dark_mode,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
surface.write_to_png(&mut data).unwrap();
|
||||
|
|
|
@ -9,7 +9,7 @@ use rust_embed::{EmbeddedFile, RustEmbed};
|
|||
use crate::SharedState;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "web"]
|
||||
#[folder = "static"]
|
||||
struct StaticFiles;
|
||||
|
||||
async fn static_files(uri: Uri) -> impl IntoResponse {
|
||||
|
|
|
@ -26,11 +26,8 @@
|
|||
<main class="container">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<img src="logo?dark_mode=false&text=false" style="height: 50px" class="light-only" />
|
||||
<img src="logo?dark_mode=true&text=false" style="height: 50px" class="dark-only" />
|
||||
<strong>MakerLab Murnau Logo generator</strong>
|
||||
</li>
|
||||
<li><img src="logo" style="height: 50px" class="light-only" /> <img src="logo?dark_mode=true"
|
||||
style="height: 50px" class="dark-only" /> <strong>MakerLab Murnau Logo generator</strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://makerlab-murnau.de">MakerLab Website</a></li>
|
||||
|
@ -51,10 +48,6 @@
|
|||
</label>
|
||||
<input type="color" id="logo_background_color" name="background_color" value="">
|
||||
</div>
|
||||
<label for="logo_text">
|
||||
<input type="checkbox" id="logo_text" name="text" role="switch">
|
||||
Add text
|
||||
</label>
|
||||
<label for="logo_dark_mode">
|
||||
<input type="checkbox" id="logo_dark_mode" name="dark_mode" role="switch">
|
||||
Dark mode
|
0
web/pico.min.css → static/pico.min.css
vendored
0
web/pico.min.css → static/pico.min.css
vendored
Loading…
Reference in a new issue