#!/usr/bin/env python3 """Generate app icon for Saat Invest (1024x1024, anti-aliased 4x supersample). Desain: bg hijau zamrud gradient, garis grafik naik putih tebal, titik akhir, badge 'Rp' kecil. Simpan ke flutter/assets/icon/app_icon.png.""" import math from PIL import Image, ImageDraw, ImageFont SS = 4 # supersample factor SIZE = 1024 W = H = SIZE * SS # --- background gradient (emerald) --- top = (0x16, 0x8a, 0x63) # lebih terang bot = (0x07, 0x53, 0x3a) # lebih gelap img = Image.new('RGB', (W, H)) px = img.load() for y in range(H): t = y / (H - 1) r = int(top[0] + (bot[0] - top[0]) * t) g = int(top[1] + (bot[1] - top[1]) * t) b = int(top[2] + (bot[2] - top[2]) * t) for x in range(W): px[x, y] = (r, g, b) d = ImageDraw.Draw(img) WHITE = (255, 255, 255, 255) SOFT = (255, 255, 255, 128) def pt(x, y): """convert normalized (0..1) to supersampled px coords.""" return (x * W, y * H) # --- line chart (naik) --- # area chart di tengah (safe zone); baseline 0.78 -> puncak 0.34 line_pts = [ (0.18, 0.72), (0.36, 0.58), (0.52, 0.62), (0.68, 0.46), (0.82, 0.34), ] pts_px = [pt(x, y) for x, y in line_pts] # stroke tebal dengan join bulat lw = int(0.078 * W) d.line(pts_px, fill=WHITE, width=lw, joint='curve') # titik pada tiap vertex (bulatan kecil) r = int(0.042 * W) for (x, y) in pts_px: d.ellipse([x - r, y - r, x + r, y + r], fill=WHITE) # area di bawah garis (fill lembut) base_y = 0.80 * H poly = [(pts_px[0][0], base_y)] + list(pts_px) + [(pts_px[-1][0], base_y)] overlay = Image.new('RGBA', (W, H), (0, 0, 0, 0)) od = ImageDraw.Draw(overlay) od.polygon(poly, fill=(255, 255, 255, 45)) img = Image.alpha_composite(img.convert('RGBA'), overlay) d = ImageDraw.Draw(img) # --- badge 'Rp' --- # posisikan di kiri-atas dari ujung grafik, tetap dalam safe zone font_path = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf' fsize = int(0.105 * W) f = ImageFont.truetype(font_path, fsize) text = 'Rp' bbox = d.textbbox((0, 0), text, font=f) tw = bbox[2] - bbox[0] th = bbox[3] - bbox[1] # badge bulat: di atas segmen terakhir, kiri dari titik ujung bcx = pts_px[-2][0] * 0.92 + pts_px[-1][0] * 0.08 - 0.10 * W bcy = pts_px[-2][1] * 0.5 + pts_px[-1][1] * 0.5 - 0.20 * H br = int(0.105 * W) d.ellipse([bcx - br, bcy - br, bcx + br, bcy + br], fill=(255, 255, 255, 240)) # teks Rp hijau tua di badge d.text((bcx - tw / 2 - bbox[0], bcy - th / 2 - bbox[1]), text, font=f, fill=(0x07, 0x53, 0x3a, 255)) # --- downscale to 1024 (Lanczos) --- out = img.resize((SIZE, SIZE), Image.Resampling.LANCZOS).convert('RGB') import os os.makedirs('flutter/assets/icon', exist_ok=True) out.save('flutter/assets/icon/app_icon.png') print('saved flutter/assets/icon/app_icon.png', out.size)