aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-08-06 17:02:18 +0200
committerblasty <blasty@local>2026-08-06 17:02:18 +0200
commit45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69 (patch)
tree15d01087b92e5408e190491ca0395b55f5e4dbce /tools
parenthelp: reach the cheatsheet with H as well as F1 (diff)
downloadida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.tar.gz
ida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.tar.xz
ida-tui-45ba9cf2f448b8c0e9548fce08ced7cea3d9cf69.zip
splash: blasty's transparent logo, and stop guessing the cell aspectHEADmain
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.py90
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())