107 lines
3.3 KiB
Python
107 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
BRAND_DIR = ROOT / "nouri" / "static" / "brand"
|
|
|
|
BG_TOP = "#F6C394"
|
|
BG_BOTTOM = "#DE9862"
|
|
BOWL = "#FFF7EF"
|
|
STROKE = "#8C533B"
|
|
|
|
|
|
def rounded_gradient_icon(size: int, *, maskable: bool = False) -> Image.Image:
|
|
image = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
|
draw = ImageDraw.Draw(image)
|
|
radius = int(size * (0.28 if maskable else 0.24))
|
|
|
|
for y in range(size):
|
|
blend = y / max(size - 1, 1)
|
|
r1, g1, b1 = ImageColorTuple(BG_TOP)
|
|
r2, g2, b2 = ImageColorTuple(BG_BOTTOM)
|
|
color = (
|
|
int(r1 + (r2 - r1) * blend),
|
|
int(g1 + (g2 - g1) * blend),
|
|
int(b1 + (b2 - b1) * blend),
|
|
255,
|
|
)
|
|
draw.line((0, y, size, y), fill=color)
|
|
|
|
mask = Image.new("L", (size, size), 0)
|
|
ImageDraw.Draw(mask).rounded_rectangle((0, 0, size - 1, size - 1), radius=radius, fill=255)
|
|
image.putalpha(mask)
|
|
|
|
inset = int(size * (0.11 if maskable else 0.13))
|
|
inner = [inset, inset, size - inset, size - inset]
|
|
draw.rounded_rectangle(inner, radius=int(radius * 0.84), outline=(255, 255, 255, 54), width=max(2, size // 80))
|
|
|
|
bowl_top = int(size * 0.24)
|
|
bowl_left = int(size * 0.27)
|
|
bowl_right = int(size * 0.73)
|
|
bowl_bottom = int(size * 0.68)
|
|
draw.rounded_rectangle(
|
|
(bowl_left, bowl_top, bowl_right, bowl_bottom),
|
|
radius=int(size * 0.16),
|
|
fill=BOWL,
|
|
)
|
|
draw.rounded_rectangle(
|
|
(int(size * 0.31), int(size * 0.31), int(size * 0.69), int(size * 0.60)),
|
|
radius=int(size * 0.12),
|
|
fill=(239, 195, 159, 64),
|
|
)
|
|
|
|
bowl_curve_top = int(size * 0.56)
|
|
draw.pieslice(
|
|
(int(size * 0.24), bowl_curve_top, int(size * 0.76), int(size * 0.84)),
|
|
start=0,
|
|
end=180,
|
|
fill=(247, 179, 125, 255),
|
|
)
|
|
|
|
line_width = max(4, size // 26)
|
|
steam = [
|
|
(0.50, 0.31),
|
|
(0.56, 0.31),
|
|
(0.56, 0.40),
|
|
(0.45, 0.50),
|
|
(0.45, 0.58),
|
|
]
|
|
draw.line([(int(size * x), int(size * y)) for x, y in steam], fill=STROKE, width=line_width, joint="curve")
|
|
draw.line(
|
|
[(int(size * 0.45), int(size * 0.58)), (int(size * 0.56), int(size * 0.58))],
|
|
fill=STROKE,
|
|
width=line_width,
|
|
)
|
|
return image
|
|
|
|
|
|
def ImageColorTuple(hex_color: str) -> tuple[int, int, int]:
|
|
hex_color = hex_color.lstrip("#")
|
|
return tuple(int(hex_color[index:index + 2], 16) for index in (0, 2, 4))
|
|
|
|
|
|
def badge_icon(size: int) -> Image.Image:
|
|
image = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
|
draw = ImageDraw.Draw(image)
|
|
draw.rounded_rectangle((0, 0, size - 1, size - 1), radius=size // 3, fill=BG_BOTTOM)
|
|
draw.ellipse((size * 0.18, size * 0.18, size * 0.82, size * 0.82), fill=BOWL)
|
|
draw.rectangle((size * 0.34, size * 0.52, size * 0.66, size * 0.63), fill=STROKE)
|
|
return image
|
|
|
|
|
|
def save_assets() -> None:
|
|
BRAND_DIR.mkdir(parents=True, exist_ok=True)
|
|
rounded_gradient_icon(180).save(BRAND_DIR / "pwa-180.png")
|
|
rounded_gradient_icon(192).save(BRAND_DIR / "pwa-192.png")
|
|
rounded_gradient_icon(512).save(BRAND_DIR / "pwa-512.png")
|
|
rounded_gradient_icon(512, maskable=True).save(BRAND_DIR / "pwa-maskable-512.png")
|
|
badge_icon(96).save(BRAND_DIR / "pwa-badge.png")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
save_assets()
|