Compare commits

..

No commits in common. "ce6c45e2857050315a3aa6534a39495ed8a8ab32" and "75e569182423fe0a87d671166a0620520cc473b2" have entirely different histories.

10 changed files with 65 additions and 84 deletions

Binary file not shown.

Before

(image error) Size: 26 KiB

View file

@ -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() {

View file

@ -1,6 +1,3 @@
#![feature(const_trait_impl)]
#![feature(const_convert)]
use axum::Router;
use std::net::SocketAddr;

View file

@ -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(())
}

View file

@ -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();

View file

@ -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,7 +44,13 @@ 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)
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();

View file

@ -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 {

View file

@ -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