The purple came from the old Audiobookshelf icon. Accent and button gradient now take the radio's brass and dial glow (#C27A1E, light #E8A64A, buttons #D98C2B to #A35F14), and the backgrounds, lines and greys lose their purple tint for warm ones. The blue 'new episode' dot stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
"""Draws Podlite's PNG icons for ldpi (Galaxy Mini), mdpi and hdpi.
|
|
|
|
The launcher icon (res/drawable-*/ic_launcher.png) comes from the supplied
|
|
"Podcasts Radio" icon pack (master in art/icon-master.png) and is not generated
|
|
here. The notification icon is a white silhouette of that radio, as Android
|
|
2.3's status bar expects.
|
|
|
|
Android 2.x has no vector drawables, so the player icons are rendered at 4x and
|
|
downsampled for smooth edges.
|
|
"""
|
|
import os
|
|
import sys
|
|
from PIL import Image, ImageDraw
|
|
|
|
RES = sys.argv[1]
|
|
ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
|
|
DENS = {"ldpi": 0.75, "mdpi": 1.0, "hdpi": 1.5}
|
|
AMBER = (232, 166, 74, 255) # accent_light (#E8A64A), from the radio icon's brass
|
|
WHITE = (255, 255, 255, 255)
|
|
SS = 4 # supersampling
|
|
|
|
|
|
def canvas(px):
|
|
s = px * SS
|
|
return Image.new("RGBA", (s, s), (0, 0, 0, 0)), s
|
|
|
|
|
|
def save(img, px, folder, name):
|
|
out = img.resize((px, px), Image.LANCZOS)
|
|
d = os.path.join(RES, "drawable-" + folder)
|
|
os.makedirs(d, exist_ok=True)
|
|
out.save(os.path.join(d, name + ".png"))
|
|
|
|
|
|
def status_silhouette():
|
|
"""White silhouette of the launcher icon's old radio (handle, grille, two knobs) on transparency:
|
|
Android 2.3's status bar expects a light glyph, not the colour artwork."""
|
|
S = 24 * 32 # drawn on a 24-unit grid, supersampled
|
|
u = lambda v: int(round(v * 32))
|
|
m = Image.new("L", (S, S), 0)
|
|
d = ImageDraw.Draw(m)
|
|
d.arc((u(6), u(1.2), u(18), u(11)), 200, 340, fill=255, width=u(1.8)) # carrying handle
|
|
d.rounded_rectangle((u(1.5), u(6.5), u(22.5), u(21.5)), radius=u(3.5), fill=255)
|
|
d.rounded_rectangle((u(4), u(9), u(14), u(19)), radius=u(1.2), fill=0) # grille window
|
|
for i in range(3): # grille bars
|
|
y = 10.6 + i * 2.9
|
|
d.rounded_rectangle((u(5.2), u(y), u(12.8), u(y + 1.5)), radius=u(0.7), fill=255)
|
|
for cy, r in ((11.6, 2.4), (17.0, 2.0)): # knobs as rings
|
|
d.ellipse((u(18 - r), u(cy - r), u(18 + r), u(cy + r)), fill=0)
|
|
d.ellipse((u(18 - r + 1.1), u(cy - r + 1.1), u(18 + r - 1.1), u(cy + r - 1.1)), fill=255)
|
|
out = Image.new("RGBA", (S, S), (255, 255, 255, 0))
|
|
out.putalpha(m)
|
|
return out
|
|
|
|
|
|
def status(sil, px, folder):
|
|
pad = max(1, round(px * 0.06))
|
|
inner = sil.resize((px - 2 * pad, px - 2 * pad), Image.LANCZOS)
|
|
img = Image.new("RGBA", (px, px), (0, 0, 0, 0))
|
|
img.paste(inner, (pad, pad))
|
|
d = os.path.join(RES, "drawable-" + folder)
|
|
img.save(os.path.join(d, "ic_stat.png"))
|
|
|
|
|
|
def play(px, folder, name, color):
|
|
img, s = canvas(px)
|
|
d = ImageDraw.Draw(img)
|
|
d.polygon([(s * 0.32, s * 0.2), (s * 0.32, s * 0.8), (s * 0.82, s * 0.5)], fill=color)
|
|
save(img, px, folder, name)
|
|
|
|
|
|
def pause(px, folder, name, color):
|
|
img, s = canvas(px)
|
|
d = ImageDraw.Draw(img)
|
|
d.rectangle([s * 0.26, s * 0.2, s * 0.43, s * 0.8], fill=color)
|
|
d.rectangle([s * 0.57, s * 0.2, s * 0.74, s * 0.8], fill=color)
|
|
save(img, px, folder, name)
|
|
|
|
|
|
def refresh(px, folder):
|
|
img, s = canvas(px)
|
|
d = ImageDraw.Draw(img)
|
|
w = int(s * 0.1)
|
|
box = [s * 0.2, s * 0.2, s * 0.8, s * 0.8]
|
|
d.arc(box, 30, 320, fill=WHITE, width=w)
|
|
# arrow head at the arc's end (top right)
|
|
d.polygon([(s * 0.86, s * 0.14), (s * 0.88, s * 0.48), (s * 0.56, s * 0.36)], fill=WHITE)
|
|
save(img, px, folder, "ic_refresh")
|
|
|
|
|
|
sil = status_silhouette()
|
|
for folder, k in DENS.items():
|
|
status(sil, round(25 * k), folder)
|
|
play(round(32 * k), folder, "ic_play", WHITE) # on the amber play button
|
|
pause(round(32 * k), folder, "ic_pause", WHITE)
|
|
play(round(38 * k), folder, "ic_play_small", AMBER) # mini player bar, on dark
|
|
pause(round(38 * k), folder, "ic_pause_small", AMBER)
|
|
refresh(round(30 * k), folder)
|
|
print("icons ok")
|