speckles/main.py

177 lines
3.8 KiB
Python
Raw Normal View History

2023-06-14 09:05:25 +00:00
import io
2024-08-22 13:52:32 +00:00
from perlin import CoordsGenerator
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",
"|",
"_",
]
2024-08-14 13:28:49 +00:00
marker_subs = {
"=": "$=$",
"/": "$/$",
"\\": "$\\setminus$",
"«": "$«$",
"»": "$»$",
"~": "$\\sim$",
"": "$♪$",
"": "$♫$",
"": "$\\infty$",
"": "$♡$",
"o": "$\\bigcirc$",
"": "$♠$",
"": "$♣$",
"": "$♥$",
"": "$♦$",
}
2024-08-13 14:14:29 +00:00
2023-06-14 09:05:25 +00:00
@app.get("/speckles/")
def make_wallpaper(
speckle_colours: str,
2024-08-22 13:52:32 +00:00
density: float = 0.12,
size: float = 3,
2023-06-14 09:05:25 +00:00
fileformat: str = "svg",
2024-08-22 13:52:32 +00:00
orientation: str = "landscape",
2024-10-21 11:32:10 +00:00
filename: str = "",
2024-08-22 13:52:32 +00:00
markers: str = ".",
perlin: bool = True,
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)
2024-08-14 10:55:22 +00:00
speckles_per_colour = int(x / 128 * y / 128 * density / len(markers))
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)
2024-08-22 13:52:32 +00:00
if perlin:
gen = CoordsGenerator(y, x)
2024-08-14 10:55:22 +00:00
for color, marker, size in itertools.product(
2023-06-14 09:05:25 +00:00
speckle_colours,
2024-08-14 10:55:22 +00:00
markers,
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
):
2024-08-14 13:27:35 +00:00
marker = marker_subs.get(marker, marker)
2024-08-22 13:52:32 +00:00
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)],
)
2023-06-14 09:05:25 +00:00
ax.scatter(
2024-08-22 13:52:32 +00:00
x_coords,
y_coords,
2023-06-14 09:05:25 +00:00
c=color,
s=size,
2024-08-14 10:55:22 +00:00
marker=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)
2024-10-21 11:32:10 +00:00
if filename:
2023-07-24 14:18:41 +00:00
with open(filename, "wb") as f:
f.write(buf.getbuffer())
2024-10-21 11:32:10 +00:00
buf.close()
2023-07-24 14:18:41 +00:00
return filename
else:
return StreamingResponse(content=buf, media_type=MEDIA_TYPES[fileformat])
2023-06-14 09:05:25 +00:00
if __name__ == "__main__":
2024-08-14 13:27:35 +00:00
uvicorn.run("main:app", workers=3, port=8099, reload=True)