141 líneas
5.5 KiB
Python
141 líneas
5.5 KiB
Python
"""
|
|
Genera el icono de Labmagic a partir del wordmark blanco real de Labstream.
|
|
|
|
- icono.ico / icono.png: la opción elegida (OPCION_POR_DEFECTO).
|
|
- iconos/opcion-N.ico|png: todas las opciones, por si se quiere cambiar (basta copiar una sobre icono.ico).
|
|
- iconos/opciones.png: hoja de muestra con las opciones a 256 px y a tamaño pequeño.
|
|
"""
|
|
import os
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
LOGO_BLANCO = r"C:\Users\Munka\OneDrive\Labstream\Propuestas\0_Modelo Propuestas\Logos\Logo Blanco.png"
|
|
OPCION_POR_DEFECTO = 2
|
|
|
|
ROJO = (227, 38, 44, 255)
|
|
ROJO_OSCURO = (170, 22, 28, 255)
|
|
NEGRO = (16, 16, 16, 255)
|
|
BLANCO = (255, 255, 255, 255)
|
|
SS = 4 # supermuestreo
|
|
|
|
|
|
def cargar_wordmark():
|
|
"""Devuelve (wordmark 'labstream', 'lab' solo, logo completo con STUDIO), todos RGBA blancos recortados."""
|
|
img = Image.open(LOGO_BLANCO).convert("RGBA")
|
|
w, h = img.size
|
|
full = img.crop(img.getbbox())
|
|
word = img.crop((0, 0, w, int(h * 0.66)))
|
|
word = word.crop(word.getbbox())
|
|
lab = word.crop((0, 0, int(word.width * 0.295), word.height))
|
|
lab = lab.crop(lab.getbbox())
|
|
return word, lab, full
|
|
|
|
|
|
def fondo(size, color, radio=0.22, borde=None, grosor=0.035, inset=0.065):
|
|
s = size * SS
|
|
img = Image.new("RGBA", (s, s), (0, 0, 0, 0))
|
|
d = ImageDraw.Draw(img)
|
|
d.rounded_rectangle((0, 0, s - 1, s - 1), radius=int(s * radio), fill=color)
|
|
if borde:
|
|
i = int(s * inset)
|
|
d.rounded_rectangle((i, i, s - 1 - i, s - 1 - i), radius=int(s * (radio - inset * 0.8)),
|
|
outline=borde, width=max(1, int(s * grosor)))
|
|
return img
|
|
|
|
|
|
def pegar_centrado(base, art, ancho_rel, dy_rel=0.0):
|
|
s = base.width
|
|
ratio = art.height / art.width
|
|
w = int(s * ancho_rel)
|
|
h = int(w * ratio)
|
|
art = art.resize((w, h), Image.LANCZOS)
|
|
x = (s - w) // 2
|
|
y = int((s - h) / 2 + s * dy_rel)
|
|
base.alpha_composite(art, (x, y))
|
|
return base
|
|
|
|
|
|
def punto(base, cx_rel, cy_rel, r_rel, color):
|
|
s = base.width
|
|
d = ImageDraw.Draw(base)
|
|
cx, cy, r = s * cx_rel, s * cy_rel, s * r_rel
|
|
d.ellipse((cx - r, cy - r, cx + r, cy + r), fill=color)
|
|
return base
|
|
|
|
|
|
def opcion(n, size):
|
|
word, lab, full = cargar_wordmark()
|
|
if n == 1: # Rojo, borde blanco fino, wordmark blanco
|
|
base = fondo(size, ROJO, borde=BLANCO)
|
|
return pegar_centrado(base, word, 0.74)
|
|
if n == 2: # Rojo, wordmark grande "lab" + punto REC blanco
|
|
base = fondo(size, ROJO, borde=BLANCO)
|
|
pegar_centrado(base, lab, 0.56, dy_rel=-0.03)
|
|
return punto(base, 0.5, 0.78, 0.055, BLANCO)
|
|
if n == 3: # Negro con borde rojo, wordmark blanco y punto rojo
|
|
base = fondo(size, NEGRO, borde=ROJO, grosor=0.05)
|
|
pegar_centrado(base, word, 0.74, dy_rel=-0.04)
|
|
return punto(base, 0.5, 0.74, 0.05, ROJO)
|
|
if n == 4: # Rojo oscuro degradado, logo completo (labstream + STUDIO)
|
|
s = size * SS
|
|
grad = Image.new("RGBA", (s, s), ROJO)
|
|
gd = ImageDraw.Draw(grad)
|
|
for y in range(s):
|
|
t = y / s
|
|
c = tuple(int(ROJO[i] * (1 - t) + ROJO_OSCURO[i] * t) for i in range(3)) + (255,)
|
|
gd.line((0, y, s, y), fill=c)
|
|
mask = fondo(size, BLANCO)
|
|
base = Image.new("RGBA", (s, s), (0, 0, 0, 0))
|
|
base.paste(grad, (0, 0), mask)
|
|
ImageDraw.Draw(base).rounded_rectangle((int(s * 0.065), int(s * 0.065), s - 1 - int(s * 0.065), s - 1 - int(s * 0.065)),
|
|
radius=int(s * 0.17), outline=BLANCO, width=max(1, int(s * 0.03)))
|
|
return pegar_centrado(base, full, 0.72)
|
|
raise ValueError(n)
|
|
|
|
|
|
def render(n, size):
|
|
return opcion(n, size).resize((size, size), Image.LANCZOS)
|
|
|
|
|
|
def guardar_ico(n, ruta_ico, ruta_png):
|
|
sizes = [16, 24, 32, 48, 64, 128, 256]
|
|
imgs = [render(n, s) for s in sizes]
|
|
imgs[-1].save(ruta_ico, format="ICO", sizes=[(s, s) for s in sizes], append_images=imgs[:-1])
|
|
render(n, 64).save(ruta_png)
|
|
|
|
|
|
def hoja(ruta):
|
|
"""Hoja de muestra: cada opción a 256 px, y a 48/32/16 px para ver cómo se lee en pequeño."""
|
|
try:
|
|
font = ImageFont.truetype("C:/Windows/Fonts/segoeui.ttf", 22)
|
|
fontb = ImageFont.truetype("C:/Windows/Fonts/segoeuib.ttf", 26)
|
|
except Exception: # noqa: BLE001
|
|
font = fontb = ImageFont.load_default()
|
|
nombres = {1: "1 · Rojo, borde blanco, wordmark", 2: "2 · Rojo, 'lab' grande + punto",
|
|
3: "3 · Negro, borde rojo, wordmark", 4: "4 · Rojo degradado, logo completo"}
|
|
col_w, pad = 360, 40
|
|
sheet = Image.new("RGBA", (col_w * 4 + pad, 470), (24, 24, 24, 255))
|
|
d = ImageDraw.Draw(sheet)
|
|
d.text((pad, 14), "Opciones de icono para Labmagic", fill=(240, 240, 240, 255), font=fontb)
|
|
for i, n in enumerate((1, 2, 3, 4)):
|
|
x0 = pad + i * col_w
|
|
sheet.alpha_composite(render(n, 256), (x0, 60))
|
|
y = 340
|
|
xx = x0
|
|
for s in (48, 32, 16):
|
|
sheet.alpha_composite(render(n, s), (xx, y + (48 - s) // 2))
|
|
xx += s + 14
|
|
d.text((x0, 405), nombres[n], fill=(200, 200, 200, 255), font=font)
|
|
sheet.save(ruta)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
out_dir = os.path.join(HERE, "iconos")
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
for n in (1, 2, 3, 4):
|
|
guardar_ico(n, os.path.join(out_dir, f"opcion-{n}.ico"), os.path.join(out_dir, f"opcion-{n}.png"))
|
|
guardar_ico(OPCION_POR_DEFECTO, os.path.join(HERE, "icono.ico"), os.path.join(HERE, "icono.png"))
|
|
hoja(os.path.join(out_dir, "opciones.png"))
|
|
print("icono por defecto: opción", OPCION_POR_DEFECTO, "->", os.path.join(HERE, "icono.ico"))
|