#!/usr/bin/env python3 """Generate UIDefEdit launcher icons as PNG files (pure Python, no Pillow).""" import struct, zlib, math, os def make_png(width, height, pixels): """Create a PNG file from RGBA pixel data. pixels = list of (r,g,b,a) tuples, row-major.""" def chunk(ctype, data): c = ctype + data return struct.pack('>I', len(data)) + c + struct.pack('>I', zlib.crc32(c) & 0xffffffff) raw = b'' for y in range(height): raw += b'\x00' # filter byte: None for x in range(width): r, g, b, a = pixels[y * width + x] raw += struct.pack('BBBB', r, g, b, a) sig = b'\x89PNG\r\n\x1a\n' ihdr = struct.pack('>IIBBBBB', width, height, 8, 6, 0, 0, 0) # 8-bit RGBA return sig + chunk(b'IHDR', ihdr) + chunk(b'IDAT', zlib.compress(raw, 9)) + chunk(b'IEND', b'') def draw_icon(size): """Draw the UIDefEdit icon at given size. Returns list of (r,g,b,a) tuples.""" pixels = [(0, 0, 0, 0)] * (size * size) s = size def put(x, y, r, g, b, a=255): if 0 <= x < s and 0 <= y < s: pixels[y * s + x] = (r, g, b, a) def fill_rect(x0, y0, x1, y1, r, g, b, a=255): for yy in range(max(0, int(y0)), min(s, int(y1))): for xx in range(max(0, int(x0)), min(s, int(x1))): pixels[yy * s + xx] = (r, g, b, a) def fill_rounded_rect(x0, y0, x1, y1, radius, r, g, b, a=255): """Fill a rounded rectangle.""" for yy in range(max(0, int(y0)), min(s, int(y1))): for xx in range(max(0, int(x0)), min(s, int(x1))): # Check corners inside = True # Top-left corner if xx < x0 + radius and yy < y0 + radius: dx = xx - (x0 + radius) dy = yy - (y0 + radius) if dx*dx + dy*dy > radius*radius: inside = False # Top-right corner elif xx >= x1 - radius and yy < y0 + radius: dx = xx - (x1 - radius - 1) dy = yy - (y0 + radius) if dx*dx + dy*dy > radius*radius: inside = False # Bottom-left corner elif xx < x0 + radius and yy >= y1 - radius: dx = xx - (x0 + radius) dy = yy - (y1 - radius - 1) if dx*dx + dy*dy > radius*radius: inside = False # Bottom-right corner elif xx >= x1 - radius and yy >= y1 - radius: dx = xx - (x1 - radius - 1) dy = yy - (y1 - radius - 1) if dx*dx + dy*dy > radius*radius: inside = False if inside: pixels[yy * s + xx] = (r, g, b, a) def draw_rect_outline(x0, y0, x1, y1, r, g, b, a=255, thick=1): """Draw rectangle outline.""" for t in range(thick): for xx in range(int(x0), int(x1)): put(xx, int(y0) + t, r, g, b, a) put(xx, int(y1) - 1 - t, r, g, b, a) for yy in range(int(y0), int(y1)): put(int(x0) + t, yy, r, g, b, a) put(int(x1) - 1 - t, yy, r, g, b, a) # Scale factor f = s / 192.0 # Background: rounded teal square margin = int(8 * f) corner_r = int(32 * f) fill_rounded_rect(margin, margin, s - margin, s - margin, corner_r, 30, 136, 160, 255) # Teal # Subtle gradient overlay (darker at bottom) for yy in range(int(margin), s - int(margin)): t = (yy - margin) / max(1, (s - 2*margin)) darken = int(30 * t) for xx in range(int(margin), s - int(margin)): pr, pg, pb, pa = pixels[yy * s + xx] if pa > 0: pixels[yy * s + xx] = (max(0, pr - darken), max(0, pg - darken), max(0, pb - darken), pa) # Inner content area pad = int(28 * f) # --- Draw layout wireframe pattern --- # Top bar (toolbar representation) bar_h = int(18 * f) fill_rect(pad, pad, s - pad, pad + bar_h, 255, 255, 255, 180) # Left panel panel_top = pad + bar_h + int(6 * f) panel_w = int(40 * f) fill_rect(pad, panel_top, pad + panel_w, s - pad, 255, 255, 255, 100) # Main canvas area with controls canvas_left = pad + panel_w + int(6 * f) canvas_top = panel_top # Control 1: large container (gray outline, dashed effect) c1x = canvas_left + int(4 * f) c1y = canvas_top + int(4 * f) c1w = int(72 * f) c1h = int(50 * f) fill_rect(c1x, c1y, c1x + c1w, c1y + c1h, 200, 200, 220, 60) draw_rect_outline(c1x, c1y, c1x + c1w, c1y + c1h, 200, 200, 220, 160, max(1, int(1.5 * f))) # Control 2: input (blue) c2x = c1x + int(6 * f) c2y = c1y + int(6 * f) c2w = int(58 * f) c2h = int(14 * f) fill_rect(c2x, c2y, c2x + c2w, c2y + c2h, 80, 140, 220, 200) draw_rect_outline(c2x, c2y, c2x + c2w, c2y + c2h, 120, 170, 240, 255, max(1, int(f))) # Control 3: button (green) c3x = c1x + int(6 * f) c3y = c2y + c2h + int(6 * f) c3w = int(30 * f) c3h = int(14 * f) fill_rect(c3x, c3y, c3x + c3w, c3y + c3h, 80, 190, 120, 200) draw_rect_outline(c3x, c3y, c3x + c3w, c3y + c3h, 100, 220, 140, 255, max(1, int(f))) # Control 4: another button (green) c4x = c3x + c3w + int(4 * f) c4y = c3y c4w = int(24 * f) c4h = int(14 * f) fill_rect(c4x, c4y, c4x + c4w, c4y + c4h, 80, 190, 120, 200) draw_rect_outline(c4x, c4y, c4x + c4w, c4y + c4h, 100, 220, 140, 255, max(1, int(f))) # Control 5: list/grid (orange) c5x = canvas_left + int(4 * f) c5y = c1y + c1h + int(8 * f) c5w = int(72 * f) c5h = int(40 * f) fill_rect(c5x, c5y, c5x + c5w, c5y + c5h, 220, 160, 60, 120) draw_rect_outline(c5x, c5y, c5x + c5w, c5y + c5h, 240, 180, 80, 200, max(1, int(1.5 * f))) # Grid lines inside for row in range(1, 4): ly = c5y + int(row * c5h / 4) fill_rect(c5x + int(2*f), ly, c5x + c5w - int(2*f), ly + max(1, int(f)), 240, 180, 80, 100) # Selection handles on control 2 (white squares) hs = max(2, int(4 * f)) handle_color = (255, 255, 255, 240) # corners of c2 for hx, hy in [(c2x, c2y), (c2x + c2w, c2y), (c2x, c2y + c2h), (c2x + c2w, c2y + c2h)]: fill_rect(hx - hs//2, hy - hs//2, hx + hs//2, hy + hs//2, *handle_color) # Bottom status bar status_y = s - pad - int(12 * f) fill_rect(pad, status_y, s - pad, s - pad, 255, 255, 255, 60) return pixels def main(): base = os.path.dirname(os.path.abspath(__file__)) sizes = { 'mipmap-mdpi': 48, 'mipmap-hdpi': 72, 'mipmap-xhdpi': 96, 'mipmap-xxhdpi': 144, 'mipmap-xxxhdpi': 192, } for folder, size in sizes.items(): pixels = draw_icon(size) png_data = make_png(size, size, pixels) out_path = os.path.join(base, 'res', folder, 'ic_launcher.png') os.makedirs(os.path.dirname(out_path), exist_ok=True) with open(out_path, 'wb') as f: f.write(png_data) print(f" Generated {folder}/ic_launcher.png ({size}x{size}, {len(png_data)} bytes)") print("Done! Icon files generated.") if __name__ == '__main__': main()