Primer commit del proyecto. Incluye el rediseño 1.6 (riel de pasos en la barra lateral), el actualizador con reintentos y respaldo, publicar.sh y la nueva opción de desconectar carpetas (1.6.1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
72 líneas
2.8 KiB
Python
72 líneas
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Genera static/organilab.png (256 px) y static/organilab.ico (256/48/32/16) sin dependencias:
|
||
el logo OrganiLAB, cuadrado azul redondeado con tres barras blancas."""
|
||
import os
|
||
import zlib
|
||
import struct
|
||
|
||
AQUI = os.path.dirname(os.path.abspath(__file__))
|
||
AZUL = (0x1F, 0x57, 0xD6)
|
||
|
||
|
||
def pinta(n):
|
||
"""devuelve filas RGBA del logo a n×n"""
|
||
r = n * 7 / 32 # radio de las esquinas (7/32 como el SVG)
|
||
barras = [(8, 18, 1.0), (14, 13, .85), (20, 8, .65)] # (y, ancho, opacidad) en unidades de 32
|
||
filas = []
|
||
for y in range(n):
|
||
fila = bytearray()
|
||
for x in range(n):
|
||
# cuadrado redondeado con antialias sencillo (4 muestras)
|
||
dentro = 0
|
||
for sx, sy in ((.25, .25), (.75, .25), (.25, .75), (.75, .75)):
|
||
px, py = x + sx, y + sy
|
||
cx = min(max(px, r), n - r)
|
||
cy = min(max(py, r), n - r)
|
||
if (px - cx) ** 2 + (py - cy) ** 2 <= r * r:
|
||
dentro += 1
|
||
a = dentro / 4
|
||
if a == 0:
|
||
fila += bytes((0, 0, 0, 0))
|
||
continue
|
||
col = list(AZUL)
|
||
for by, bw, op in barras:
|
||
y0, y1 = by * n / 32, (by + 4) * n / 32
|
||
x0, x1 = 7 * n / 32, (7 + bw) * n / 32
|
||
rb = 2 * n / 32
|
||
if y0 <= y + .5 < y1 and x0 <= x + .5 < x1:
|
||
# esquinas de la barra redondeadas
|
||
cx = min(max(x + .5, x0 + rb), x1 - rb)
|
||
cy = min(max(y + .5, y0 + rb), y1 - rb)
|
||
if (x + .5 - cx) ** 2 + (y + .5 - cy) ** 2 <= rb * rb:
|
||
col = [int(c + (255 - c) * op) for c in AZUL]
|
||
fila += bytes((col[0], col[1], col[2], int(255 * a)))
|
||
filas.append(bytes(fila))
|
||
return filas
|
||
|
||
|
||
def png(n):
|
||
filas = pinta(n)
|
||
raw = b"".join(b"\x00" + f for f in filas)
|
||
|
||
def chunk(t, d):
|
||
return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
|
||
return (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", n, n, 8, 6, 0, 0, 0))
|
||
+ chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
|
||
|
||
|
||
tamanos = (256, 48, 32, 16)
|
||
imgs = [png(t) for t in tamanos]
|
||
with open(os.path.join(AQUI, "static", "organilab.png"), "wb") as fh:
|
||
fh.write(imgs[0])
|
||
# ICO con PNG incrustados (válido desde Windows Vista)
|
||
cab = struct.pack("<HHH", 0, 1, len(tamanos))
|
||
off = 6 + 16 * len(tamanos)
|
||
entradas = b""
|
||
for t, im in zip(tamanos, imgs):
|
||
entradas += struct.pack("<BBBBHHII", t % 256, t % 256, 0, 0, 1, 32, len(im), off)
|
||
off += len(im)
|
||
with open(os.path.join(AQUI, "static", "organilab.ico"), "wb") as fh:
|
||
fh.write(cab + entradas + b"".join(imgs))
|
||
print("icono listo:", [len(i) for i in imgs])
|