"""The onw logo: a chip with a bold "o" dashing to the right (its left pins are speed lines). One set of shapes, drawn with Pillow (tray icon, .ico / .png) or written out as SVG (pages, README). The full design is for 48 px and up; `simple` (3 thick pins per side) stays readable at 16-32 px. python -m onw.logo regenerate onw/web/icon.ico, icon.png, icon.svg """ import os BLUE, GRAY, WHITE = (24, 104, 240), (128, 132, 142), (255, 255, 255) BADGE = {"running": (46, 160, 67), "loading": (219, 150, 20), "failed": (200, 50, 50)} BOX = (70, 90, 846) # viewBox x, y, size of the design space (traced from the 1024 px original) def shapes(simple=False): """(kind, coords, width) in design units: 'rect' = rounded chip body, 'line' = round-capped bar, 'o' = the letter.""" s = [("rect", (332, 256, 844, 767, 80), 0)] if simple: w, pins = 64, (436, 588, 740) rows = (512 - 152, 512, 512 + 152) speed = [(150, 360), (95, 512), (190, 664)] o = (150, 150, 66, 70) else: w, pins = 38, (436, 512, 588, 664, 740) rows = (360, 436, 512, 588, 664) speed = [(268, 360), (124, 436), (209, 512), (95, 588), (275, 664)] s += [("line", (181, 360, 208, 360), w), ("line", (181, 664, 212, 664), w)] # short dashes ahead o = (120, 117, 57, 67) for x in pins: s += [("line", (x, 212, x, 300), w), ("line", (x, 815, x, 720), w)] for y in rows: s.append(("line", (891, y, 800, y), w)) for x, y in speed: s.append(("line", (x, y, 380, y), w)) s.append(("o", (588, 512) + o, 0)) return s def draw(size, simple=None, state=None): """RGBA image of the logo; state (running / loading / failed / anything else = stopped) adds the tray badge.""" from PIL import Image, ImageDraw if simple is None: simple = size <= 32 ss = max(4, 2048 // size) # supersample, then scale down n = size * ss k, (ox, oy, _) = n / BOX[2], BOX P = lambda x, y: ((x - ox) * k, (y - oy) * k) color = BLUE if state in (None, "running", "loading", "failed") else GRAY im = Image.new("RGBA", (n, n), (0, 0, 0, 0)) d = ImageDraw.Draw(im) for kind, c, w in shapes(simple): if kind == "rect": d.rounded_rectangle(P(*c[:2]) + P(*c[2:4]), c[4] * k, fill=color) elif kind == "line": a, b, r = P(*c[:2]), P(*c[2:]), w * k / 2 d.line(a + b, fill=color, width=round(w * k)) for x, y in (a, b): d.ellipse((x - r, y - r, x + r, y + r), fill=color) else: (cx, cy), (rx, ry, hx, hy) = P(*c[:2]), (v * k for v in c[2:]) d.ellipse((cx - rx, cy - ry, cx + rx, cy + ry), fill=WHITE) d.ellipse((cx - hx, cy - hy, cx + hx, cy + hy), fill=color) if state in BADGE: # status dot, cut out of the chip's corner (cx, cy), r = P(800, 800), 118 * k g = r + 44 * k d.ellipse((cx - g, cy - g, cx + g, cy + g), fill=(0, 0, 0, 0)) d.ellipse((cx - r, cy - r, cx + r, cy + r), fill=BADGE[state]) return im.resize((size, size), Image.LANCZOS) def svg(simple=False): ox, oy, n = BOX h = "#%02x%02x%02x" % BLUE L = [f''] for kind, c, w in shapes(simple): if kind == "rect": x0, y0, x1, y1, r = c L.append(f'') elif kind == "line": L.append(f'') else: cx, cy, rx, ry, hx, hy = c L.append(f'' f'') return "".join(L) + "" def main(): web = os.path.join(os.path.dirname(os.path.abspath(__file__)), "web") sizes = [16, 20, 24, 32, 40, 48, 64, 128, 256] big = draw(256) big.save(os.path.join(web, "icon.ico"), sizes=[(s, s) for s in sizes], append_images=[draw(s) for s in sizes[:-1]]) big.save(os.path.join(web, "icon.png")) with open(os.path.join(web, "icon.svg"), "w", encoding="utf8", newline="\n") as f: f.write(svg() + "\n") print("icon.ico, icon.png, icon.svg ->", web) if __name__ == "__main__": main()