#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-3-Clause # # Script to generate text graphics using the "small" (HUD) font. # from PIL import Image from glob import glob import sys import re from image_dimensions import * from tint import image_tint DIMENSION_MATCH_RE = re.compile(r"(\d+)[x,](\d+)") class SmallTextGenerator(object): def __init__(self): self.get_font_widths() # Width of a space character in pixels. SPACE_WIDTH = 4 # Height of the font. FONT_HEIGHT = 8 # Regexp to match dimensions/x,y coordinate pair. def compile_kerning_table(self, kerning_table): """Given a dictionary of kerning patterns, compile Regexps.""" result = {} for pattern, adjust in kerning_table.items(): result[re.compile(pattern)] = adjust return result def get_font_widths(self): charfiles = glob("../stcfn*.png") self.char_widths = {} for c in range(128): filename = self.char_filename(chr(c)) if filename not in charfiles: continue w, _ = get_image_dimensions(filename) self.char_widths[chr(c)] = w def __contains__(self, c): return c in self.char_widths def char_width(self, c): return self.char_widths[c] def char_filename(self, c): return "../stcfn%03d.png" % (ord(c)) def draw_for_text(self, image, text, x, y): text = text.upper() new_image = image.copy() x1, y1 = x, y for c in text: if c == "\n": y1 += self.FONT_HEIGHT x1 = x elif c == " ": x1 += self.SPACE_WIDTH if c not in self: continue filename = self.char_filename(c) char_image = Image.open(filename) char_image.load() new_image = self.paste_image(new_image, char_image, x1, y1) x1 += self.char_width(c) return new_image def paste_image(self, image, src, x, y): int_image = Image.new("RGBA", image.size, (0, 0, 0, 0)) int_image.paste(src, (x, y)) new_image = Image.alpha_composite(image, int_image) return new_image def parse_command_line(args): if len(args) < 4 or (len(args) % 2) != 0: return None result = {"filename": args[0], "background": None, "strings": []} m = DIMENSION_MATCH_RE.match(args[1]) if not m: return None result["dimensions"] = (int(m.group(1)), int(m.group(2))) i = 2 while i < len(args): if args[i] == "-background": result["background"] = args[i + 1] i += 2 continue m = DIMENSION_MATCH_RE.match(args[i]) if not m: return None xy = (int(m.group(1)), int(m.group(2))) result["strings"].append((xy, args[i + 1])) i += 2 return result if __name__ == "__main__": args = parse_command_line(sys.argv[1:]) if not args: print("Usage: smtextgen [...text commands...]") print("Where each text command looks like:") print(" [x,y] [text]") sys.exit(0) smallfont = SmallTextGenerator() if args["background"] is not None: background_image = Image.open(args["background"]) background_image.load() background_image = background_image.convert("RGBA") image = Image.new("RGBA", args["dimensions"], (0, 0, 0, 0)) for xy, string in args["strings"]: # Allow contents of a file to be included with special prefix: if string.startswith("include:"): with open(string[8:]) as f: string = f.read() # Allow special notation to indicate an image file to just draw # rather than rendering a string. if string.startswith("file:"): src_image = Image.open(string[5:]) src_image.load() image = smallfont.paste_image(image, src_image, xy[0], xy[1]) else: image = smallfont.draw_for_text(image, string, xy[0], xy[1]) if args["background"] is not None: image = Image.alpha_composite(background_image, image) image.save(args["filename"])