diff options
| author | blasty <blasty@local> | 2026-08-06 17:02:18 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-08-06 17:02:18 +0200 |
| commit | 45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69 (patch) | |
| tree | 15d01087b92e5408e190491ca0395b55f5e4dbce /tools | |
| parent | help: reach the cheatsheet with H as well as F1 (diff) | |
| download | ida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.tar.gz ida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.tar.xz ida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.zip | |
The artwork is now a proper transparent PNG with soft edges (24% of its pixels
carry partial alpha) instead of opaque art on black with a stray full-width
scan line along the bottom. Cropped to its content and resized 1024 -> 768px,
which halves the file and costs nothing visible; logo-trans.png keeps the
master for future re-renders.
Two things the new art exposed, both wrong before it:
fit() assumed cells were 1:2. This terminal reports 9x22, i.e. 1:2.44. The old
logo was 474x516 -- close enough to the assumption that nobody noticed -- but a
square image at the hardcoded 60x33 would have been visibly stretched. The
graphics query now asks for the cell size too (CSI 16 t rides along in the same
round trip, before the DA1 that already synchronises it) and fit() uses the
answer.
The footprint was a constant. logo_cells() derives it from the artwork and the
measured cell size, so the art can be replaced without anyone remembering to
edit a number.
logo.ans was stale: the block-art fallback for terminals that can't draw an
image was still the OLD artwork, scan line included. tools/make_logo_ans.py
regenerates it from logo.png so the two cannot drift again. It understands
alpha -- a transparent cell emits no colour and lets the terminal background
through, and a cell with only one opaque half uses the matching half block so
the pixel lands on the correct side.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/make_logo_ans.py | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/tools/make_logo_ans.py b/tools/make_logo_ans.py new file mode 100644 index 0000000..9736e30 --- /dev/null +++ b/tools/make_logo_ans.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +"""Regenerate logo.ans (the block-art splash) from logo.png. + +logo.ans is the fallback for terminals that can't draw an image, so it has to be +rendered from the same artwork or the two drift apart -- which is exactly what +happened when logo.png was replaced and the old block art kept a scan line that +no longer existed. + +Each cell is a lower half-block: the background colour paints the upper pixel, +the foreground the lower one, so one cell carries two pixel rows. Transparent +pixels emit no colour at all, letting the terminal background show through, and +a cell whose lower pixel is transparent uses an upper half-block instead so the +one opaque pixel still lands on the correct half. + +Needs Pillow, so run it with a python that has it (NOT ~/ida-venv): + + /usr/bin/python3 tools/make_logo_ans.py [--cols 60] [-o logo.ans] +""" +from __future__ import annotations + +import argparse +import os +import sys + +from PIL import Image + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +ALPHA_ON = 128 # at/above this a pixel counts as present + +UPPER, LOWER = "\u2580", "\u2584" # upper half block, lower half block + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--png", default=os.path.join(REPO, "logo.png")) + ap.add_argument("-o", "--out", default=os.path.join(REPO, "logo.ans")) + ap.add_argument("--cols", type=int, default=60) + ap.add_argument("--cell", default="9x22", + help="terminal cell size WxH in px, for the aspect ratio") + args = ap.parse_args() + + cw, ch = (int(v) for v in args.cell.lower().split("x")) + im = Image.open(args.png).convert("RGBA") + bbox = im.getchannel("A").getbbox() + if bbox: + im = im.crop(bbox) + w, h = im.size + cols = args.cols + # two pixel rows per cell, and cells are taller than they are wide + rows = max(1, round((h / w) * cols * cw / ch)) + im = im.resize((cols, rows * 2), Image.LANCZOS) + px = im.load() + + out: list[str] = [] + for r in range(rows): + line = [] + prev = None + for c in range(cols): + top = px[c, r * 2] + bot = px[c, r * 2 + 1] + t_on, b_on = top[3] >= ALPHA_ON, bot[3] >= ALPHA_ON + if not t_on and not b_on: + sgr, ch_ = "\033[0m", " " + elif t_on and b_on: + sgr = (f"\033[38;2;{bot[0]};{bot[1]};{bot[2]}m" + f"\033[48;2;{top[0]};{top[1]};{top[2]}m") + ch_ = LOWER + elif b_on: # only the lower pixel is present + sgr = f"\033[0m\033[38;2;{bot[0]};{bot[1]};{bot[2]}m" + ch_ = LOWER + else: # only the upper pixel is present + sgr = f"\033[0m\033[38;2;{top[0]};{top[1]};{top[2]}m" + ch_ = UPPER + if sgr != prev: + line.append(sgr) + prev = sgr + line.append(ch_) + line.append("\033[0m") + out.append("".join(line)) + + text = "\n".join(out) + "\n" + with open(args.out, "w", encoding="utf-8") as f: + f.write(text) + print(f"{args.png} {w}x{h} -> {args.out} {cols}x{rows} cells " + f"({len(text):,} bytes, cell {cw}x{ch})") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) |
