Generate Hydra Fastfetch emblem and verify packaged ASCII art
This commit is contained in:
+17
-5
@@ -352,14 +352,25 @@ def terminal_ux_iso():
|
||||
return bytes(data)
|
||||
|
||||
|
||||
def verify_terminal_ux_branding(output, errors):
|
||||
rendered = re.sub(r'\x1b\[[0-?]*[ -/]*[@-~]', '', output)
|
||||
def verify_terminal_ux_branding(output, errors, logo):
|
||||
ansi = r'\x1b\[[0-?]*[ -/]*[@-~]'
|
||||
rendered = re.sub(ansi, '', output)
|
||||
if errors.strip() or re.search(r'\b(error|failed|unknown module)\b', rendered, re.I):
|
||||
raise SmokeError('Installed default Fastfetch emitted errors: ' + (errors or rendered)[-1500:])
|
||||
if not re.search(r'\bOS\s*:\s*Hydra OS\b', rendered):
|
||||
raise SmokeError('Installed default Fastfetch did not render the Hydra OS pretty name')
|
||||
if 'H Y D R A O S' not in rendered or rendered.count('(o >') != 3:
|
||||
raise SmokeError('Installed default Fastfetch did not render the three-headed Hydra logo')
|
||||
expected = [line.rstrip() for line in re.sub(r'\$[1-9]|' + ansi, '', logo).splitlines()
|
||||
if line.strip()]
|
||||
caption = 'H Y D R A O S'
|
||||
if (not any(line.strip() == caption for line in expected)
|
||||
or not any(line.strip() != caption for line in expected)):
|
||||
raise SmokeError('Packaged Fastfetch logo must contain art and the Hydra OS caption')
|
||||
width = max(map(len, expected))
|
||||
lines = iter(rendered.splitlines())
|
||||
for row in expected:
|
||||
if not any(line[:width].rstrip() == row
|
||||
and (len(line) <= width or line[width].isspace()) for line in lines):
|
||||
raise SmokeError('Installed default Fastfetch did not render the complete packaged Hydra logo')
|
||||
return rendered
|
||||
|
||||
|
||||
@@ -414,7 +425,8 @@ fetch = subprocess.run(['fastfetch', '--pipe', 'false', '--show-errors'],
|
||||
capture_output=True, text=True, timeout=30)
|
||||
if fetch.returncode:
|
||||
raise SmokeError('Installed default Fastfetch failed: ' + fetch.stderr[-1500:])
|
||||
fastfetch_output = verify_terminal_ux_branding(fetch.stdout, fetch.stderr)
|
||||
fastfetch_output = verify_terminal_ux_branding(
|
||||
fetch.stdout, fetch.stderr, Path('/usr/share/hydra/fastfetch.txt').read_text())
|
||||
config_hash = hashlib.sha256(Path('/etc/fastfetch/config.jsonc').read_bytes()).hexdigest()
|
||||
logo_hash = hashlib.sha256(Path('/usr/share/hydra/fastfetch.txt').read_bytes()).hexdigest()
|
||||
base = Path(tempfile.mkdtemp(prefix='hux-', dir='/tmp'))
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert the generated Hydra silhouette to Fastfetch ASCII using Pillow.
|
||||
|
||||
Run from the repository root with Python + Pillow (development only):
|
||||
python3 dev/render-logo.py
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
RAMP = ' .:-=+*#%@' # '$' is reserved for Fastfetch color placeholders.
|
||||
CAPTION = 'H Y D R A O S'
|
||||
|
||||
|
||||
def render(source, columns):
|
||||
# This is a single-color mark: opacity, not luminance, defines its shape.
|
||||
# Threshold near-transparent generation noise before reducing the image.
|
||||
with Image.open(source) as image:
|
||||
mask = image.convert('RGBA').getchannel('A').point(
|
||||
lambda value: 255 if value > 160 else 0)
|
||||
bounds = mask.getbbox()
|
||||
if bounds is None:
|
||||
raise ValueError('The source image has no visible silhouette')
|
||||
mask = mask.crop(bounds)
|
||||
# A terminal character is approximately twice as tall as it is wide.
|
||||
rows = max(1, round(mask.height / mask.width * columns * 0.5))
|
||||
pixels = mask.resize((columns, rows), Image.Resampling.LANCZOS)
|
||||
lines = []
|
||||
for y in range(rows):
|
||||
line = ''
|
||||
for x in range(columns):
|
||||
coverage = pixels.getpixel((x, y)) / 255
|
||||
level = min(9, max(0, round((coverage - 0.09) / 0.82 * 9)))
|
||||
line += RAMP[level]
|
||||
lines.append(line.rstrip())
|
||||
return '$1' + '\n'.join(lines) + '\n\n$2' + CAPTION.center(columns).rstrip() + '\n'
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--source', type=Path,
|
||||
default=ROOT / 'assets/branding/hydra-mark.png')
|
||||
parser.add_argument('--output', type=Path,
|
||||
default=ROOT / 'image/rootfs/usr/share/hydra/fastfetch.txt')
|
||||
parser.add_argument('--columns', type=int, default=44)
|
||||
args = parser.parse_args()
|
||||
if not len(CAPTION) <= args.columns <= 100:
|
||||
parser.error('columns must be between 13 and 100')
|
||||
args.output.write_text(render(args.source, args.columns), encoding='ascii')
|
||||
print(args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user