So on a recommendation from shmoo on Libera, I decided to get myself a Pro duck.ai account for just whatever bullshit I feel like doing. It’s actually so much better than Google’s Gemini subscription shit. Way better. Infinitely better.

Anyways, I vibecoded a zoitechat script that allows you to send “The Draw Font” ascii spam to whatever channel. It works pretty well I guess. I fuckin dig it. I dunno how well it works in edge cases, so if anyone has any updates please do pass along.

Anyway, without further ado:

# tdf_send.py — TheDraw .TDF font sender for ZoiteChat

import os
import re
import shlex
import struct
import zoitechat

__module_name__ = "TDF Send"
__module_version__ = "1.6"
__module_description__ = "Render and send TheDraw .TDF fonts"

TDF_MARKER = b"\x55\xaa\x00\xff"
FIRST_FONT_OFFSET = 20
FONT_HEADER_SIZE = 213
UNDEFINED_OFFSET = 0xffff

DOS_TO_IRC = [1, 2, 3, 10, 4, 6, 7, 15, 14, 12, 9, 11, 4, 13, 8, 0]

OUTLINE_MAP = {
    "A": 0xCD, "B": 0xC4, "C": 0xB3, "D": 0xBA,
    "E": 0xD5, "F": 0xBB, "G": 0xD6, "H": 0xBF,
    "I": 0xC8, "J": 0xBE, "K": 0xC0, "L": 0xBD,
    "M": 0xB5, "N": 0xC7,
}

PC_DISPLAY_GLYPHS = {
    1: "☺", 2: "☻", 3: "♥", 4: "♦", 5: "♣", 6: "♠",
    7: "•", 8: "◘", 9: "○", 10: "◙", 11: "♂", 12: "♀",
    14: "♫", 15: "☼", 16: "►", 17: "◄", 18: "↕", 19: "‼",
    20: "¶", 21: "§", 22: "▬", 23: "↨", 24: "↑", 25: "↓",
    26: "→", 27: "←", 28: "∟", 29: "↔", 30: "▲", 31: "▼",
    127: "⌂",
}

IRC_COLOR_RE = re.compile(r"\x03\d{2},\d{2}")

loaded_fonts = {}
loaded_file = None


def cp437_to_utf8(value):
    return PC_DISPLAY_GLYPHS.get(
        value,
        bytes([value]).decode("cp437", errors="replace"),
    )


def font_key(name):
    return name.replace("\x00", "").replace("\u00A0", " ").strip().casefold()


def display_width(text):
    return len(IRC_COLOR_RE.sub("", text).replace("\x0f", ""))


def compact_irc_colors(line):
    result = []
    last_color = None
    pos = 0

    while pos < len(line):
        match = IRC_COLOR_RE.match(line, pos)

        if match:
            color = match.group(0)

            if color != last_color:
                result.append(color)
                last_color = color

            pos = match.end()
        else:
            result.append(line[pos])
            pos += 1

    return "".join(result)


class TDFFont:
    def __init__(self, name, font_type, spacing, data, offsets):
        self.name = name
        self.font_type = font_type
        self.spacing = max(0, spacing - 1)
        self.data = data
        self.offsets = offsets

    def character(self, char):
        if char == " ":
            return ["    "]

        code = ord(char)

        if code < 33 or code > 126:
            return [char]

        offset = self.offsets[code - 33]

        if offset == UNDEFINED_OFFSET or offset + 2 > len(self.data):
            return [char]

        width = self.data[offset]
        height = self.data[offset + 1]
        pos = offset + 2
        row = ""
        row_columns = 0
        rows = []

        if width == 0:
            return [" "]

        while pos < len(self.data):
            value = self.data[pos]
            pos += 1

            if value == 0:
                if row or not rows:
                    rows.append(row + (" " * max(0, width - row_columns)))
                break

            if value == 13:
                rows.append(row + (" " * max(0, width - row_columns)))
                row = ""
                row_columns = 0
                continue

            color_value = None

            if self.font_type == 2:
                if pos >= len(self.data):
                    break
                color_value = self.data[pos]
                pos += 1

            if self.font_type == 0:
                reference = chr(value)

                if reference == "@":
                    glyph = " "
                elif reference == "O":
                    glyph = "\u00A0"
                elif reference == "&":
                    continue
                elif reference in OUTLINE_MAP:
                    glyph = cp437_to_utf8(OUTLINE_MAP[reference])
                else:
                    glyph = cp437_to_utf8(value)
            else:
                glyph = cp437_to_utf8(value)

            if color_value is not None:
                fg = DOS_TO_IRC[color_value & 0x0F]
                bg = DOS_TO_IRC[(color_value >> 4) & 0x07]
                row += "\x03{:02d},{:02d}{}".format(fg, bg, glyph)
            else:
                row += glyph

            row_columns += 1

        while len(rows) < height:
            rows.append(" " * width)

        return rows or [" " * width]

    def render(self, text):
        rendered = []

        for source_line in text.splitlines() or [""]:
            glyphs = [self.character(char) for char in source_line]
            widths = [
                max((display_width(row) for row in glyph), default=1)
                for glyph in glyphs
            ]
            height = max((len(glyph) for glyph in glyphs), default=1)
            output = [""] * height

            for index, glyph in enumerate(glyphs):
                for row_index in range(height):
                    if row_index < len(glyph):
                        output[row_index] += glyph[row_index]
                    else:
                        output[row_index] += " " * widths[index]

                if index != len(glyphs) - 1:
                    for row_index in range(height):
                        output[row_index] += " " * self.spacing

            rendered.extend(row.rstrip() + "\x0f" for row in output)

        return rendered


def load_tdf(path):
    global loaded_fonts, loaded_file

    with open(path, "rb") as source:
        blob = source.read()

    if not blob.startswith(b"\x13TheDraw FONTS file\x1a"):
        raise ValueError("Not a valid TheDraw .TDF file.")

    fonts = {}
    pos = FIRST_FONT_OFFSET

    while pos + FONT_HEADER_SIZE <= len(blob):
        if blob[pos:pos + 4] != TDF_MARKER:
            break

        name_length = min(blob[pos + 4], 12)
        name = blob[pos + 5:pos + 5 + name_length].decode(
            "cp437",
            errors="replace",
        ).split("\x00", 1)[0].strip()

        font_type = blob[pos + 21]
        spacing = blob[pos + 22]
        block_size = struct.unpack_from("<H", blob, pos + 23)[0]
        offsets = list(struct.unpack_from("<94H", blob, pos + 25))

        data_start = pos + FONT_HEADER_SIZE
        data_end = min(data_start + block_size, len(blob))

        if name:
            fonts[font_key(name)] = TDFFont(
                name,
                font_type,
                spacing,
                blob[data_start:data_end],
                offsets,
            )

        pos = data_start + block_size

    if not fonts:
        raise ValueError("No readable fonts were found in this file.")

    loaded_fonts = fonts
    loaded_file = os.path.abspath(path)


def get_font(name):
    font = loaded_fonts.get(font_key(name))

    if font is None:
        raise ValueError(
            'Font "{}" was not found. Use /TDFFONTS to list fonts.'.format(name)
        )

    return font


def send_lines(context, lines):
    for line in lines:
        line = compact_irc_colors(line.replace("\r", "").replace("\n", ""))

        if len(line.encode("utf-8")) > 350:
            raise ValueError(
                "A rendered line is too wide for IRC. "
                "Use shorter text or a narrower font."
            )

        context.command("SAY " + line)


def tdfload_cb(word, word_eol, userdata):
    try:
        if len(word) < 2:
            raise ValueError("Usage: /TDFLOAD /full/path/to/fonts.tdf")

        load_tdf(os.path.expanduser(word_eol[1]))
        zoitechat.prnt(
            "Loaded {} font(s) from {}".format(len(loaded_fonts), loaded_file)
        )
    except Exception as error:
        zoitechat.prnt("TDF error: {}".format(error))

    return zoitechat.EAT_ALL


def tdffonts_cb(word, word_eol, userdata):
    if not loaded_fonts:
        zoitechat.prnt("No TDF file loaded. Use /TDFLOAD <file>.")
    else:
        zoitechat.prnt(
            "Loaded fonts: " +
            ", ".join(sorted(font.name for font in loaded_fonts.values()))
        )

    return zoitechat.EAT_ALL


def tdf_cb(word, word_eol, userdata):
    try:
        args = shlex.split(word_eol[1])

        if len(args) < 2:
            raise ValueError('Usage: /TDF "Font Name" text')

        send_lines(
            zoitechat.get_context(),
            get_font(args[0]).render(" ".join(args[1:])),
        )
    except Exception as error:
        zoitechat.prnt("TDF error: {}".format(error))

    return zoitechat.EAT_ALL


def tdfto_cb(word, word_eol, userdata):
    try:
        args = shlex.split(word_eol[1])

        if len(args) < 3:
            raise ValueError(
                'Usage: /TDFTO <#channel-or-nick> "Font Name" text'
            )

        context = zoitechat.find_context(channel=args[0])

        if context is None:
            raise ValueError(
                'No open channel or query named "{}".'.format(args[0])
            )

        send_lines(context, get_font(args[1]).render(" ".join(args[2:])))
    except Exception as error:
        zoitechat.prnt("TDF error: {}".format(error))

    return zoitechat.EAT_ALL


zoitechat.hook_command(
    "TDFLOAD",
    tdfload_cb,
    help="/TDFLOAD <file> Load a TheDraw .TDF collection",
)

zoitechat.hook_command(
    "TDFFONTS",
    tdffonts_cb,
    help="/TDFFONTS List loaded fonts",
)

zoitechat.hook_command(
    "TDF",
    tdf_cb,
    help='/TDF "Font Name" <text> Send to the active channel or query',
)

zoitechat.hook_command(
    "TDFTO",
    tdfto_cb,
    help='/TDFTO <#channel-or-nick> "Font Name" <text>',
)

zoitechat.prnt("TDF Send loaded. Use /TDFLOAD <file>.")