Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I wrote a library to convert to BDF #6

Open
ctrlcctrlv opened this issue Aug 14, 2022 · 0 comments
Open

I wrote a library to convert to BDF #6

ctrlcctrlv opened this issue Aug 14, 2022 · 0 comments

Comments

@ctrlcctrlv
Copy link

Is this of interest? If so I can publish it

from collections.abc import Generator, Iterable
from copy import deepcopy
from more_itertools import chunked

from bitarray import bitarray
from bdflib.model import Font as BDFLibFont
from ibm437 import to_ibm437
import bdflib.writer
import bdflib.xlfd
import os.path


class Font:
    def __init__(
        self,
        filename: str,
        strict=True,
        bits_per_scanline_byte: int = 8,
        bytes_per_scanline: int = 1,
    ):
        self.filename = filename
        self.strict = strict
        self.bpsb = bits_per_scanline_byte
        self.bpsl = bytes_per_scanline
        self.populate_filename_info()
        self.fontbuf = bitarray()
        with open(filename, "rb") as f:
            self.fontbuf.fromfile(f)
        self.populate_glyphs()

    def populate_filename_info(self) -> int:
        temp = self.filename.split(".F")
        assert len(temp) == 2, "Bad filename!"
        fontname, self.scanlines_per = temp
        assert all(
            c.isdigit() for c in self.scanlines_per
        ), "Non-digits in scanline specifier!"
        self.scanlines_per = int(self.scanlines_per)
        assert (
            0 < self.scanlines_per <= 32
        ), f"Scanline count {self.scanlines_per} not between 0…32!"
        assert self.bpsl in (1, 2), f"Only 1 or 2 bytes per scanline allowed!"
        self.family = fontname.split(os.path.sep)[-1]
        return self.scanlines_per

    def _glyphs_gen(self) -> Generator[Generator[list[int]]]:
        return chunked(
            list(chunked(list(self.fontbuf), self.bpsb * self.bpsl, strict=True)),
            self.scanlines_per,
            strict=False,
        )

    def populate_glyphs(self) -> None:
        self.glyphs = list()
        for glyph in self._glyphs_gen():
            self.glyphs.append(glyph)

    @staticmethod
    def expand_glyph(
        glyph: Iterable[Iterable[list[int]]], boxdrawing: bool = True
    ) -> Generator[list[str]]:

        if boxdrawing:
            chars = " █"
        else:
            chars = "01"

        def expand_line(line: list[int]) -> str:
            return "".join([chars[1] if i else chars[0] for i in line])

        for l in glyph:
            yield expand_line(l)

    def expanded_glyphs(self, **kwargs) -> Generator[str]:
        for g in self.glyphs:
            yield "\n".join(Font.expand_glyph(g, **kwargs))

    def pretty(self) -> str:
        return "\n\n".join(
            [
                "Glyph 0x{i:X} ({c}):\n\n{g}".format(c=to_ibm437(i), i=i, g=g)
                for i, g in enumerate(self.expanded_glyphs())
            ]
        )


class BDF(BDFLibFont):
    @staticmethod
    def _convert_glyph_data(glyph):
        return list(reversed([int("".join([str(bb) for bb in b]), 2) for b in glyph]))

    def __init__(self, font: Font):
        self.name = font.family.replace("&", "").encode("ascii")
        self.ptSize = font.scanlines_per
        self.xdpi = self.ydpi = 100
        super().__init__(self.name, self.ptSize, self.xdpi, self.ydpi)
        for i, glyph in enumerate(font.glyphs):
            cp = ord(to_ibm437(i))
            glyph_data = dict(
                codepoint=cp, bbW=font.bpsb, bbH=font.scanlines_per, advance=font.bpsb
            )
            gname = "uni{:04X}".format(cp).encode("ascii")
            gdata = BDF._convert_glyph_data(glyph)
            self.new_glyph_from_data(gname, gdata, **glyph_data)


def main():
    import sys

    _, FONT = sys.argv
    assert ".F" in FONT
    parsed = Font(FONT)
    # print(parsed.pretty())
    bdf = BDF(parsed)
    bdflib.xlfd.fix(bdf)
    bdf.properties[bdflib.xlfd.CHARSET_REGISTRY] = b"Unicode"
    bdflib.writer.write_bdf(bdf, sys.stdout.buffer)


if __name__ == "__main__":
    main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant