speckles/main.py
2024-10-21 13:32:10 +02:00

177 lines
3.8 KiB
Python

import io
from perlin import CoordsGenerator
from typing import Literal
import itertools
import logging
import random
import matplotlib.pyplot as plt
import numpy as np
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
app = FastAPI(title="Speckles API", root_path="/images")
origins = [
"http://localhost",
"http://localhost:3000",
"https://localhost",
"https://0124816.xyz",
"http://0124816.xyz:3001",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
MEDIA_TYPES = {
"png": "image/png",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"svg": "image/svg+xml",
"pdf": "application/pdf",
}
Marker = Literal[
".",
",",
"o",
"v",
"^",
"<",
">",
"1",
"2",
"3",
"4",
"8",
"s",
"p",
"P",
"*",
"h",
"H",
"+",
"x",
"X",
"D",
"d",
"|",
"_",
]
marker_subs = {
"=": "$=$",
"/": "$/$",
"\\": "$\\setminus$",
"«": "$«$",
"»": "$»$",
"~": "$\\sim$",
"": "$♪$",
"": "$♫$",
"": "$\\infty$",
"": "$♡$",
"o": "$\\bigcirc$",
"": "$♠$",
"": "$♣$",
"": "$♥$",
"": "$♦$",
}
@app.get("/speckles/")
def make_wallpaper(
speckle_colours: str,
density: float = 0.12,
size: float = 3,
fileformat: str = "svg",
orientation: str = "landscape",
filename: str = "",
markers: str = ".",
perlin: bool = True,
):
if fileformat not in MEDIA_TYPES:
return
speckle_colours = speckle_colours.split(",")
background = speckle_colours.pop(0)
if orientation == "portrait":
x, y = (1080, 1920)
elif orientation == "landscape":
x, y = (1920, 1080)
elif "x" in orientation:
resolution = orientation.split("x")
if len(resolution) != 2:
logging.critical("input resolution has more or less than 2 dimensions")
return
x, y = resolution
if all([x.isdigit(), y.isdigit()]):
x, y = int(x), int(y)
else:
return
else:
x, y = (1920, 1080)
speckles_per_colour = int(x / 128 * y / 128 * density / len(markers))
fig, ax = plt.subplots(figsize=(x / 120, y / 120), facecolor=background)
ax.set_facecolor(background)
[spine.set_color(background) for spine in ax.spines.values()]
ax.set_xticks([])
ax.set_yticks([])
ax.margins(0, 0)
if perlin:
gen = CoordsGenerator(y, x)
for color, marker, size in itertools.product(
speckle_colours,
markers,
np.logspace(0, size, 10, base=np.exp(2)),
):
marker = marker_subs.get(marker, marker)
if perlin:
x_coords, y_coords = gen.pick(speckles_per_colour)
else:
x_coords, y_coords = (
[random.random() * x / 8 for _ in range(speckles_per_colour)],
[random.random() * y / 8 for _ in range(speckles_per_colour)],
)
ax.scatter(
x_coords,
y_coords,
c=color,
s=size,
marker=marker,
)
fig.tight_layout()
# plt.xlim(0, x)
# plt.ylim(0, y)
# plt.axis("off")
buf = io.BytesIO()
fig.savefig(
buf,
format=fileformat,
dpi=128,
bbox_inches="tight",
pad_inches=0,
)
buf.seek(0)
if filename:
with open(filename, "wb") as f:
f.write(buf.getbuffer())
buf.close()
return filename
else:
return StreamingResponse(content=buf, media_type=MEDIA_TYPES[fileformat])
if __name__ == "__main__":
uvicorn.run("main:app", workers=3, port=8099, reload=True)