# -*- coding: utf-8 -*- """画套餐底栏 PNG:盒子线稿 / 实心底,微信自定义栏必须用本地图。""" import struct import zlib from pathlib import Path SIZE = 81 def png(rgba_rows): def chunk(tag, data): return struct.pack('>I', len(data)) + tag + data + struct.pack('>I', zlib.crc32(tag + data) & 0xFFFFFFFF) raw = b''.join(b'\x00' + bytes(row) for row in rgba_rows) return ( b'\x89PNG\r\n\x1a\n' + chunk(b'IHDR', struct.pack('>IIBBBBB', SIZE, SIZE, 8, 6, 0, 0, 0)) + chunk(b'IDAT', zlib.compress(raw, 9)) + chunk(b'IEND', b'') ) def blank(): return [[0, 0, 0, 0] * SIZE for _ in range(SIZE)] def set_px(rows, x, y, a=255): if 0 <= x < SIZE and 0 <= y < SIZE: i = x * 4 rows[y][i:i + 4] = [28, 25, 23, a] def line(rows, x0, y0, x1, y1, w=3): steps = max(abs(x1 - x0), abs(y1 - y0), 1) for i in range(steps + 1): t = i / steps x = int(round(x0 + (x1 - x0) * t)) y = int(round(y0 + (y1 - y0) * t)) for dx in range(-w // 2, w // 2 + 1): for dy in range(-w // 2, w // 2 + 1): set_px(rows, x + dx, y + dy) def rect(rows, x, y, w, h, r=4, fill=False): if fill: for yy in range(y, y + h): for xx in range(x, x + w): set_px(rows, xx, yy) return line(rows, x + r, y, x + w - r, y) line(rows, x + w, y + r, x + w, y + h - r) line(rows, x + w - r, y + h, x + r, y + h) line(rows, x, y + h - r, x, y + r) def write_icons(out_dir): out = Path(out_dir) outline = blank() # 盒身 rect(outline, 16, 30, 49, 38, 5) line(outline, 16, 44, 65, 44) line(outline, 40, 30, 40, 68) line(outline, 24, 30, 40, 16) line(outline, 40, 16, 56, 30) (out / 'package.png').write_bytes(png(outline)) filled = blank() rect(filled, 16, 26, 49, 42, 4, fill=True) line(filled, 24, 26, 40, 12) line(filled, 40, 12, 56, 26) (out / 'package-fill.png').write_bytes(png(filled)) if __name__ == '__main__': here = Path(__file__).resolve().parents[1] / 'static' / 'tabbar' / 'v2' write_icons(here) print('wrote', here)