Banner lettering (JIMMY KIMMEL LIVE): new Tools/gen/generate_banner_texture.py draws the exact title with Pillow + Liberation Sans Bold - an image model would mangle a trademark string, and Qwen-Image 2.1 is research-only. Gold JIMMY / KIMMEL / LIVE stacked on a crimson ground. ue_hero_facade_import.py generalises import_albedo to import_texture and wires the banner into M_Facade_Banner_Ref as Base Color (tiling 1.0), replacing the flat dark tint with a brighter red per the owner's 'less dark, more bright'. Re-rendered all three ReviewMap staging shots (front, oblique, portals) and updated their Screenshots/README.md status rows. The hero facade rework is now closed at 'surface detail that reads at 45 m'. The remaining elevation work - volute capital depth, lattice grille depth, and the full realism pass - is deferred to 0.9.0 per the owner, and the 0.9.0 hero item records the hand-off.
89 lines
3.1 KiB
Python
89 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate the JIMMY KIMMEL LIVE banner texture for the hero facade.
|
|
|
|
The three event banners are flat panels; the lettering is text and cannot be
|
|
read as geometry at 45 m. An image model would mangle a specific trademark
|
|
string, so the text is drawn here with Pillow and a system font instead:
|
|
deterministic, exact, and (unlike Qwen-Image 2.1) not research-only.
|
|
|
|
The banner face is 1.35 m wide x 6.2 m tall (aspect 1:4.59). The texture is
|
|
written at 512 x 2304 (aspect 1:4.5), a 2% stretch that is invisible at the
|
|
review distance.
|
|
|
|
python3 Tools/gen/generate_banner_texture.py
|
|
python3 Tools/gen/generate_banner_texture.py --out Art/textures/generated/T_Banner_KIMMEL.png
|
|
|
|
Requires Pillow (host-only tool, not a gate; standard library is not enough to
|
|
rasterise a font). The text is a trademark reproduced for internal development
|
|
review only - record it in THIRD_PARTY_NOTICES.md before any public build.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
# Banner face aspect: 1.35 m wide x 6.2 m tall. 512 x 2304 keeps that to within 2 %.
|
|
WIDTH = 512
|
|
HEIGHT = 2304
|
|
|
|
# sRGB colours. The banner is a deep event red, the lettering is gold; both match the
|
|
# photographs (and the owner's "less dark, more bright" direction for the elevation).
|
|
BANNER = (186, 24, 24)
|
|
GOLD = (232, 198, 90)
|
|
|
|
FONT_BOLD = "/usr/share/fonts/liberation-sans-fonts/LiberationSans-Bold.ttf"
|
|
FONT_REGULAR = "/usr/share/fonts/liberation-sans-fonts/LiberationSans-Regular.ttf"
|
|
|
|
# Three stacked words, as the real vertical banners arrange the title. `size` is the
|
|
# font height in texture pixels; the block is centred vertically in the banner.
|
|
LINES = [
|
|
("JIMMY", 150, FONT_BOLD),
|
|
("KIMMEL", 150, FONT_BOLD),
|
|
("LIVE", 120, FONT_REGULAR),
|
|
]
|
|
LINE_GAP = 70 # pixels between baselines beyond the font ascent
|
|
|
|
|
|
def _font(path: str, size: int) -> ImageFont.FreeTypeFont:
|
|
if not os.path.exists(path):
|
|
raise SystemExit(f"font missing: {path}")
|
|
return ImageFont.truetype(path, size)
|
|
|
|
|
|
def draw_banner(out: str) -> None:
|
|
img = Image.new("RGB", (WIDTH, HEIGHT), BANNER)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
fonts = [(text, size, _font(path, size)) for text, size, path in LINES]
|
|
|
|
# Measure the whole block so it sits centred vertically in the 6.2 m banner.
|
|
ascents = [f.getbbox(text)[3] for text, _, f in fonts]
|
|
block_h = sum(ascents) + LINE_GAP * (len(fonts) - 1)
|
|
y = (HEIGHT - block_h) // 2
|
|
|
|
for text, size, font in fonts:
|
|
bbox = font.getbbox(text)
|
|
text_w = bbox[2] - bbox[0]
|
|
x = (WIDTH - text_w) // 2 - bbox[0]
|
|
draw.text((x, y), text, font=font, fill=GOLD)
|
|
y += bbox[3] + LINE_GAP
|
|
|
|
os.makedirs(os.path.dirname(os.path.abspath(out)) or ".", exist_ok=True)
|
|
img.save(out)
|
|
print(f"wrote {out} ({WIDTH}x{HEIGHT})")
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"--out", default="Art/textures/generated/T_Banner_KIMMEL.png")
|
|
args = parser.parse_args()
|
|
draw_banner(args.out)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|