speckles/main.py

146 lines
3.2 KiB
Python
Raw Normal View History

2023-06-14 09:05:25 +00:00
import io
2024-08-13 14:14:29 +00:00
from typing import Literal
2023-06-14 09:05:25 +00:00
import itertools
2023-07-24 14:18:41 +00:00
import logging
2023-06-14 09:05:25 +00:00
import random
import matplotlib.pyplot as plt
import numpy as np
import uvicorn
2023-07-24 14:18:41 +00:00
from fastapi import FastAPI
2023-06-14 09:05:25 +00:00
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",
}
2024-08-13 14:14:29 +00:00
Marker = Literal[
".",
",",
"o",
"v",
"^",
"<",
">",
"1",
"2",
"3",
"4",
"8",
"s",
"p",
"P",
"*",
"h",
"H",
"+",
"x",
"X",
"D",
"d",
"|",
"_",
]
2023-06-14 09:05:25 +00:00
@app.get("/speckles/")
def make_wallpaper(
speckle_colours: str,
density: float | None = 0.12,
2023-07-10 07:14:05 +00:00
size: float | None = 3,
2023-06-14 09:05:25 +00:00
fileformat: str = "svg",
2023-07-10 07:14:05 +00:00
orientation: str | None = "landscape",
2023-07-24 14:18:41 +00:00
local: bool = False,
2024-08-13 14:14:29 +00:00
marker: str | None = ".",
2023-06-14 09:05:25 +00:00
):
2024-08-13 14:14:29 +00:00
if fileformat not in MEDIA_TYPES:
2023-06-14 09:05:25 +00:00
return
speckle_colours = speckle_colours.split(",")
background = speckle_colours.pop(0)
2023-07-10 07:14:05 +00:00
if orientation == "portrait":
x, y = (1080, 1920)
elif orientation == "landscape":
x, y = (1920, 1080)
elif "x" in orientation:
resolution = orientation.split("x")
2023-07-24 14:18:41 +00:00
if len(resolution) != 2:
2023-07-10 07:14:05 +00:00
logging.critical("input resolution has more or less than 2 dimensions")
return
2023-07-24 14:18:41 +00:00
x, y = resolution
2023-07-10 07:14:05 +00:00
if all([x.isdigit(), y.isdigit()]):
2023-07-24 14:18:41 +00:00
x, y = int(x), int(y)
2023-07-10 07:14:05 +00:00
else:
return
else:
x, y = (1920, 1080)
speckles_per_colour = int(x / 128 * y / 128 * density)
2023-06-14 09:05:25 +00:00
2023-07-10 07:14:05 +00:00
fig, ax = plt.subplots(figsize=(x / 120, y / 120), facecolor=background)
2023-06-14 09:05:25 +00:00
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, size in itertools.product(
speckle_colours,
2023-07-10 07:14:05 +00:00
np.logspace(0, size, 10, base=np.exp(2)),
2023-06-14 09:05:25 +00:00
):
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,
2024-08-13 14:14:29 +00:00
marker=random.choice(marker),
2023-06-14 09:05:25 +00:00
)
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)
2023-07-24 14:18:41 +00:00
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])
2023-06-14 09:05:25 +00:00
buf.close()
if __name__ == "__main__":
uvicorn.run("main:app", workers=2, port=8099, reload=False)