speckles/main.py
2024-08-14 14:19:48 +00:00

169 lines
3.6 KiB
Python

import io
import os
import matplotlib
from typing import Literal
import itertools
import logging
import random
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
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 | None = 0.12,
size: float | None = 3,
fileformat: str = "svg",
orientation: str | None = "landscape",
local: bool = False,
markers: str | None = ".",
):
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)
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)
ax.scatter(
[random.random() * x / 8 for _ in range(speckles_per_colour)],
[random.random() * y / 8 for _ in range(speckles_per_colour)],
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 local:
filename = f"speckles.{fileformat}"
with open(filename, "wb") as f:
f.write(buf.getbuffer())
return filename
else:
return StreamingResponse(content=buf, media_type=MEDIA_TYPES[fileformat])
buf.close()
if __name__ == "__main__":
uvicorn.run("main:app", workers=3, port=8099, reload=True)