"""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} LILAC = (188, 138, 252, 255) # the icon's sound-wave colour (#BC8AFC) 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 purple play button pause(round(32 * k), folder, "ic_pause", WHITE) play(round(38 * k), folder, "ic_play_small", LILAC) # mini player bar, on dark pause(round(38 * k), folder, "ic_pause_small", LILAC) refresh(round(30 * k), folder) print("icons ok")