gen_icon.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #!/usr/bin/env python3
  2. """Generate UIDefEdit launcher icons as PNG files (pure Python, no Pillow)."""
  3. import struct, zlib, math, os
  4. def make_png(width, height, pixels):
  5. """Create a PNG file from RGBA pixel data. pixels = list of (r,g,b,a) tuples, row-major."""
  6. def chunk(ctype, data):
  7. c = ctype + data
  8. return struct.pack('>I', len(data)) + c + struct.pack('>I', zlib.crc32(c) & 0xffffffff)
  9. raw = b''
  10. for y in range(height):
  11. raw += b'\x00' # filter byte: None
  12. for x in range(width):
  13. r, g, b, a = pixels[y * width + x]
  14. raw += struct.pack('BBBB', r, g, b, a)
  15. sig = b'\x89PNG\r\n\x1a\n'
  16. ihdr = struct.pack('>IIBBBBB', width, height, 8, 6, 0, 0, 0) # 8-bit RGBA
  17. return sig + chunk(b'IHDR', ihdr) + chunk(b'IDAT', zlib.compress(raw, 9)) + chunk(b'IEND', b'')
  18. def draw_icon(size):
  19. """Draw the UIDefEdit icon at given size. Returns list of (r,g,b,a) tuples."""
  20. pixels = [(0, 0, 0, 0)] * (size * size)
  21. s = size
  22. def put(x, y, r, g, b, a=255):
  23. if 0 <= x < s and 0 <= y < s:
  24. pixels[y * s + x] = (r, g, b, a)
  25. def fill_rect(x0, y0, x1, y1, r, g, b, a=255):
  26. for yy in range(max(0, int(y0)), min(s, int(y1))):
  27. for xx in range(max(0, int(x0)), min(s, int(x1))):
  28. pixels[yy * s + xx] = (r, g, b, a)
  29. def fill_rounded_rect(x0, y0, x1, y1, radius, r, g, b, a=255):
  30. """Fill a rounded rectangle."""
  31. for yy in range(max(0, int(y0)), min(s, int(y1))):
  32. for xx in range(max(0, int(x0)), min(s, int(x1))):
  33. # Check corners
  34. inside = True
  35. # Top-left corner
  36. if xx < x0 + radius and yy < y0 + radius:
  37. dx = xx - (x0 + radius)
  38. dy = yy - (y0 + radius)
  39. if dx*dx + dy*dy > radius*radius:
  40. inside = False
  41. # Top-right corner
  42. elif xx >= x1 - radius and yy < y0 + radius:
  43. dx = xx - (x1 - radius - 1)
  44. dy = yy - (y0 + radius)
  45. if dx*dx + dy*dy > radius*radius:
  46. inside = False
  47. # Bottom-left corner
  48. elif xx < x0 + radius and yy >= y1 - radius:
  49. dx = xx - (x0 + radius)
  50. dy = yy - (y1 - radius - 1)
  51. if dx*dx + dy*dy > radius*radius:
  52. inside = False
  53. # Bottom-right corner
  54. elif xx >= x1 - radius and yy >= y1 - radius:
  55. dx = xx - (x1 - radius - 1)
  56. dy = yy - (y1 - radius - 1)
  57. if dx*dx + dy*dy > radius*radius:
  58. inside = False
  59. if inside:
  60. pixels[yy * s + xx] = (r, g, b, a)
  61. def draw_rect_outline(x0, y0, x1, y1, r, g, b, a=255, thick=1):
  62. """Draw rectangle outline."""
  63. for t in range(thick):
  64. for xx in range(int(x0), int(x1)):
  65. put(xx, int(y0) + t, r, g, b, a)
  66. put(xx, int(y1) - 1 - t, r, g, b, a)
  67. for yy in range(int(y0), int(y1)):
  68. put(int(x0) + t, yy, r, g, b, a)
  69. put(int(x1) - 1 - t, yy, r, g, b, a)
  70. # Scale factor
  71. f = s / 192.0
  72. # Background: rounded teal square
  73. margin = int(8 * f)
  74. corner_r = int(32 * f)
  75. fill_rounded_rect(margin, margin, s - margin, s - margin, corner_r,
  76. 30, 136, 160, 255) # Teal
  77. # Subtle gradient overlay (darker at bottom)
  78. for yy in range(int(margin), s - int(margin)):
  79. t = (yy - margin) / max(1, (s - 2*margin))
  80. darken = int(30 * t)
  81. for xx in range(int(margin), s - int(margin)):
  82. pr, pg, pb, pa = pixels[yy * s + xx]
  83. if pa > 0:
  84. pixels[yy * s + xx] = (max(0, pr - darken), max(0, pg - darken),
  85. max(0, pb - darken), pa)
  86. # Inner content area
  87. pad = int(28 * f)
  88. # --- Draw layout wireframe pattern ---
  89. # Top bar (toolbar representation)
  90. bar_h = int(18 * f)
  91. fill_rect(pad, pad, s - pad, pad + bar_h, 255, 255, 255, 180)
  92. # Left panel
  93. panel_top = pad + bar_h + int(6 * f)
  94. panel_w = int(40 * f)
  95. fill_rect(pad, panel_top, pad + panel_w, s - pad, 255, 255, 255, 100)
  96. # Main canvas area with controls
  97. canvas_left = pad + panel_w + int(6 * f)
  98. canvas_top = panel_top
  99. # Control 1: large container (gray outline, dashed effect)
  100. c1x = canvas_left + int(4 * f)
  101. c1y = canvas_top + int(4 * f)
  102. c1w = int(72 * f)
  103. c1h = int(50 * f)
  104. fill_rect(c1x, c1y, c1x + c1w, c1y + c1h, 200, 200, 220, 60)
  105. draw_rect_outline(c1x, c1y, c1x + c1w, c1y + c1h, 200, 200, 220, 160,
  106. max(1, int(1.5 * f)))
  107. # Control 2: input (blue)
  108. c2x = c1x + int(6 * f)
  109. c2y = c1y + int(6 * f)
  110. c2w = int(58 * f)
  111. c2h = int(14 * f)
  112. fill_rect(c2x, c2y, c2x + c2w, c2y + c2h, 80, 140, 220, 200)
  113. draw_rect_outline(c2x, c2y, c2x + c2w, c2y + c2h, 120, 170, 240, 255,
  114. max(1, int(f)))
  115. # Control 3: button (green)
  116. c3x = c1x + int(6 * f)
  117. c3y = c2y + c2h + int(6 * f)
  118. c3w = int(30 * f)
  119. c3h = int(14 * f)
  120. fill_rect(c3x, c3y, c3x + c3w, c3y + c3h, 80, 190, 120, 200)
  121. draw_rect_outline(c3x, c3y, c3x + c3w, c3y + c3h, 100, 220, 140, 255,
  122. max(1, int(f)))
  123. # Control 4: another button (green)
  124. c4x = c3x + c3w + int(4 * f)
  125. c4y = c3y
  126. c4w = int(24 * f)
  127. c4h = int(14 * f)
  128. fill_rect(c4x, c4y, c4x + c4w, c4y + c4h, 80, 190, 120, 200)
  129. draw_rect_outline(c4x, c4y, c4x + c4w, c4y + c4h, 100, 220, 140, 255,
  130. max(1, int(f)))
  131. # Control 5: list/grid (orange)
  132. c5x = canvas_left + int(4 * f)
  133. c5y = c1y + c1h + int(8 * f)
  134. c5w = int(72 * f)
  135. c5h = int(40 * f)
  136. fill_rect(c5x, c5y, c5x + c5w, c5y + c5h, 220, 160, 60, 120)
  137. draw_rect_outline(c5x, c5y, c5x + c5w, c5y + c5h, 240, 180, 80, 200,
  138. max(1, int(1.5 * f)))
  139. # Grid lines inside
  140. for row in range(1, 4):
  141. ly = c5y + int(row * c5h / 4)
  142. fill_rect(c5x + int(2*f), ly, c5x + c5w - int(2*f), ly + max(1, int(f)),
  143. 240, 180, 80, 100)
  144. # Selection handles on control 2 (white squares)
  145. hs = max(2, int(4 * f))
  146. handle_color = (255, 255, 255, 240)
  147. # corners of c2
  148. for hx, hy in [(c2x, c2y), (c2x + c2w, c2y),
  149. (c2x, c2y + c2h), (c2x + c2w, c2y + c2h)]:
  150. fill_rect(hx - hs//2, hy - hs//2, hx + hs//2, hy + hs//2,
  151. *handle_color)
  152. # Bottom status bar
  153. status_y = s - pad - int(12 * f)
  154. fill_rect(pad, status_y, s - pad, s - pad, 255, 255, 255, 60)
  155. return pixels
  156. def main():
  157. base = os.path.dirname(os.path.abspath(__file__))
  158. sizes = {
  159. 'mipmap-mdpi': 48,
  160. 'mipmap-hdpi': 72,
  161. 'mipmap-xhdpi': 96,
  162. 'mipmap-xxhdpi': 144,
  163. 'mipmap-xxxhdpi': 192,
  164. }
  165. for folder, size in sizes.items():
  166. pixels = draw_icon(size)
  167. png_data = make_png(size, size, pixels)
  168. out_path = os.path.join(base, 'res', folder, 'ic_launcher.png')
  169. os.makedirs(os.path.dirname(out_path), exist_ok=True)
  170. with open(out_path, 'wb') as f:
  171. f.write(png_data)
  172. print(f" Generated {folder}/ic_launcher.png ({size}x{size}, {len(png_data)} bytes)")
  173. print("Done! Icon files generated.")
  174. if __name__ == '__main__':
  175. main()