66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Convert the user-supplied mosque icon art to a 192x192 RGB Vela app icon.
|
|
|
|
Proven pipeline (from the sundial v0.5 icon): detect the round disc bounds on the
|
|
mid row/column of the dark-square source, crop square around disc center, apply an
|
|
anti-aliased circular alpha mask (drawn at 4x, LANCZOS down), resize to 192x192,
|
|
flatten to RGB over the dark background color.
|
|
"""
|
|
from PIL import Image, ImageDraw
|
|
|
|
SRC = "/home/iliasmohuchine/Downloads/ChatGPT Image Sep 9, 2026, 04_42_51 PM.png"
|
|
OUT = "/home/iliasmohuchine/vela-salah/src/common/icon.png"
|
|
|
|
im = Image.open(SRC).convert("RGB")
|
|
w, h = im.size
|
|
print("source:", im.size)
|
|
|
|
# detect disc bounds on mid row / mid column (background ~ rgb(17,17,24) dark)
|
|
px = im.load()
|
|
midy, midx = h // 2, w // 2
|
|
BG = px[2, 2]
|
|
print("bg color:", BG)
|
|
|
|
def is_fg(p):
|
|
return abs(p[0] - BG[0]) + abs(p[1] - BG[1]) + abs(p[2] - BG[2]) > 40
|
|
|
|
row = [x for x in range(w) if is_fg(px[x, midy])]
|
|
col = [y for y in range(h) if is_fg(px[midx, y])]
|
|
left, right = min(row), max(row)
|
|
top, bottom = min(col), max(col)
|
|
print("disc bounds: x", left, right, " y", top, bottom)
|
|
|
|
# square crop around disc center, sized to the larger span
|
|
cx, cy = (left + right) / 2, (top + bottom) / 2
|
|
span = max(right - left, bottom - top)
|
|
half = span / 2 + 2
|
|
box = (int(cx - half), int(cy - half), int(cx + half), int(cy + half))
|
|
disc = im.crop(box)
|
|
print("crop box:", box, "disc size:", disc.size)
|
|
|
|
# circular alpha mask at 4x
|
|
size = disc.size[0]
|
|
mask = Image.new("L", (size * 4, size * 4), 0)
|
|
d = ImageDraw.Draw(mask)
|
|
d.ellipse((0, 0, size * 4 - 1, size * 4 - 1), fill=255)
|
|
mask = mask.resize((size, size), Image.LANCZOS)
|
|
|
|
out = disc.convert("RGBA")
|
|
out.putalpha(mask)
|
|
out = out.resize((192, 192), Image.LANCZOS)
|
|
|
|
# flatten to RGB over dark bg
|
|
bg = Image.new("RGB", (192, 192), BG)
|
|
bg.paste(out, (0, 0), out)
|
|
bg.save(OUT, "PNG")
|
|
print("saved", OUT, bg.size, bg.mode)
|
|
|
|
# side-by-side montage for preview: source | converted
|
|
src_small = im.copy()
|
|
src_small.thumbnail((192, 192))
|
|
mont = Image.new("RGB", (192 * 2 + 24, 192), (17, 17, 24))
|
|
mont.paste(src_small, (0, 0))
|
|
mont.paste(bg, (192 + 24, 0))
|
|
mont.save("/home/iliasmohuchine/vela-salah/icon-preview.png")
|
|
print("montage saved")
|