#!/usr/bin/env python3 """Icona Shogo v2: rimozione sfondo con rembg (U2Net) + composizione kanji/mech/banner. Uso: PYTHONPATH=~/.local/pylibs-rembg python3 icon-build.py """ import sys sys.path.insert(0, '/home/enne2/.local/pylibs-rembg') from PIL import Image, ImageFilter from rembg import remove D = '/home/enne2/Dev/shogo-demo-flatpak' SRC_MECH = f'{D}/shogo_game_icon_1787156055996.jpg' SRC_BANNER = f'{D}/shogo_logo_banner_1787156448853.jpg' # ---------- 1) mech: rimozione sfondo con rembg ---------- print('rembg: rimozione sfondo mech (può richiedere un paio di minuti su CPU)...') with open(SRC_MECH, 'rb') as f: inp = f.read() out = remove(inp) mech = Image.open(__import__('io').BytesIO(out)).convert('RGBA') # pulizia: rimuovi eventuali pixel semitrasparenti isolati (opening della maschera alpha) a = mech.split()[3].point(lambda v: 0 if v < 40 else 255) mech.putalpha(a) mech.save(f'{D}/icon-mech-alpha.png') print('mech alpha:', mech.size) # ---------- 2) kanji: estrazione dei pixel rosso-scuro (fondale) ---------- src = Image.open(SRC_MECH).convert('RGBA') px = src.load() W, H = src.size kanji = Image.new('RGBA', (W, H), (0, 0, 0, 0)) kp = kanji.load() for y in range(H): for x in range(W): r, g, b, a = px[x, y] # rosso scuro del kanji: r dominante ma scuro, senza essere arancione acceso del mech if r > 55 and r < 175 and r > g + 25 and r > b + 25 and a > 100: kp[x, y] = (r, g, b, 255) kanji.save(f'{D}/icon-kanji.png') print('kanji estratto') # ---------- 3) banner: estrazione e pulizia bordi ---------- bim = Image.open(SRC_BANNER).convert('RGBA') bp = bim.load() bw, bh = bim.size xs, ys = [], [] for y in range(bh): for x in range(bw): r, g, b = bp[x, y][:3] if (r + g + b) / 3 > 40: xs.append(x); ys.append(y) x0, x1, y0, y1 = max(0, min(xs)-14), min(bw-1, max(xs)+14), max(0, min(ys)-14), min(bh-1, max(ys)+14) banner = bim.crop((x0, y0, x1+1, y1+1)).copy() b2 = banner.load() bw2, bh2 = banner.size for y in range(bh2): for x in range(bw2): r, g, b = b2[x, y][:3] if (r + g + b) / 3 <= 40: b2[x, y] = (0, 0, 0, 0) # erosione leggera dell'alpha per togliere l'alone alpha = banner.split()[3].filter(ImageFilter.MinFilter(3)) banner.putalpha(alpha) banner.save(f'{D}/icon-banner2.png') print('banner:', banner.size) # ---------- 4) composizione ---------- C = 1024 canvas = Image.new('RGBA', (C, C), (0, 0, 0, 0)) # kanji dietro, grande, opacità ~28% k2 = kanji.resize((int(C*0.95), int(C*0.95)), Image.LANCZOS) k2.putalpha(k2.split()[3].point(lambda v: int(v * 0.28))) canvas.alpha_composite(k2, ((C-k2.width)//2, (C-k2.height)//2 - int(C*0.02))) # mech sopra m = mech.resize((C, C), Image.LANCZOS) canvas.alpha_composite(m, (0, 0)) # banner in basso bw3 = int(C * 0.60) bh3 = int(banner.height * (bw3 / banner.width)) b3 = banner.resize((bw3, bh3), Image.LANCZOS) canvas.alpha_composite(b3, ((C-bw3)//2, C - bh3 - int(C*0.035))) canvas.save(f'{D}/icon-final2.png') print('composta: icon-final2.png', canvas.size)