font-compile.py
author Tero Marttila <terom@paivola.fi>
Mon, 21 Apr 2014 00:20:27 +0300
changeset 82 b5878197d017
parent 39 d7eac199d323
permissions -rw-r--r--
dmx-web: change dmx layout for more light types
def read_block (fh) :
    """
        Yield a series of non-empty lines from the given file, ignoring any leading empty lines, and stopping after the first empty line
    """

    leading = True

    for line in fh :
        if line.strip() :
            leading = False

            # yield non-empty
            yield line

        elif leading :
            # skip leading empty
            continue

        else :
            # stop on empty
            return

    else :
        # EOF
        return

def read_charblock (lines) :
    """
        Read in a char from the given lines, returning an
            (ascii, rows)

        tuple, or None, if there weren't any more blocks
    """

    # the ascii code as a char
    ascii = ''

    # row data as ints
    rows = []

    for line in lines :
        line = line.strip()

        if line.startswith(';') :
            # set ascii code
            ascii = line.replace(';', '').strip()

            if not ascii :
                print 'read_charblock', 'empty'

                # skip
                return None

            elif len(ascii) == 1 :
                print 'read_charblock', 'simplechar', ascii

            else :
                ascii = ascii.decode('string_escape')
        
                print 'read_charblock', 'decodechar', ascii

            assert len(ascii) == 1
        
        else :
            # convert
            row = line.replace('#', '1').replace('-', '0')

            print 'read_charblock', 'row', row

            # 6 columns
            assert len(row) == 6

            # from binary
            row = int(row, 2)

            rows.append(row)
    
    # got data?
    if ascii and rows :
        # 8 rows
        assert len(rows) == 8

        return ascii, rows

    else :
        # nope, empty block, EOF
        return None

def read_charblocks (fh) :
    """
        Read in all char blocks as (ascii, rows) tuples from given file
    """

    while True :
        out = read_charblock(read_block(fh))

        if out :
            yield out

        else :
            break

def decode_rows (inrows) :
    """
        Decode char def data from its 6x8 row format into the format we need (6x8 col format)
    """

    outcols = [0x00] * 6

    for rowidx, row in enumerate(inrows) :
        
        for colidx, col in enumerate(outcols) :
            # get bit from row
            bit = (row >> (5 - colidx)) & 1

            # set bit into column
            outcols[colidx] |= (bit << rowidx)

    # ok...
    return outcols

def write_chardef (fh, ascii, cols) :
    """
        Write out character definition block to given .def file, using given char code and column data
    """

    fh.write(
            ("; %r\n" % ascii)
        +   (".db %s\n" % (', '.join(bin(col) for col in cols)))
        +   ("\n")
    )

def compile_fonts (infh, outf) :
    """
        Compile char blocks from infh, writing out definitions to outf
    """

    charmap = dict()

    # decode in
    for charblock in read_charblocks(infh) :
        # unpack
        ascii, rows = charblock

        # convert
        cols = decode_rows(rows)

        # map
        charmap[ascii] = cols

        print 'compile_fonts', 'read', ascii

    # detect min/max syms
    syms = charmap.keys()
    font_start = min(syms)
    font_end = max(syms)

    assert(ord(font_start) < ord(font_end))
    
    # write out
    outf.write(
            ";; AUTOMATICALLY GENERATED - Do not edit!\n"
            ";; 8x6 font, '0' - '1', rows-by-col format\n"
        +  (".equ FONT_8x6_START = %d ; %r\n" % (ord(font_start), font_start))
        +  (".equ FONT_8x6_END = %d ; %r\n" % (ord(font_end), font_end))
        +  (".equ FONT_8x6_COLS = %d\n" % (6, ))
        +  (".equ FONT_8x6_ROWS = %d\n" % (8, ))
        +   "FONT_8x6:\n"
            "\n"
    )

    # default symbol for unknown chars
    defsym = charmap['\0']

    for char in xrange(ord(font_start), ord(font_end) + 1) :
        ascii = chr(char)
        cols = charmap.get(ascii, defsym)

        write_chardef(outf, ascii, cols)

def main () :
    import sys, getopt

    opts, args = getopt.getopt(sys.argv[1:], '')

    inpath, outpath = args

    # run
    compile_fonts(open(inpath, 'r'), open(outpath, 'w'))

if __name__ == '__main__' :
    main()