Ejemplo n.º 1
0
parser.add_argument('--infile', type=str, default='')
parser.add_argument('--outfile', type=str, default='')

# find out which operation we're asked to perform
args, unknown = parser.parse_known_args()

# get arguments for this operation
operation = monobit.OPERATIONS[args.operation[0]]
for arg, _type in operation.script_args.items():
    if _type == bool:
        parser.add_argument('--' + arg.strip('_'), dest=arg, action='store_true')
    else:
        parser.add_argument('--' + arg.strip('_'), dest=arg, type=CONVERTERS[_type])

args = parser.parse_args()

# convert arguments to type accepted by operation
fargs = {
    _name: _arg
    for _name, _arg in args.__dict__.items()
    if _arg is not None and _name in operation.script_args
}

# load, modify, save
try:
    font = monobit.load(args.infile)
    font = operation(font, **fargs)
    font.save(args.outfile)
except ValueError as exc:
    logging.error(exc)
Ejemplo n.º 2
0
#!/usr/bin/env python3

import os
import string
import tarfile
from io import TextIOWrapper

import monobit

bdf_name = 'uni_vga/u_vga16.bdf'
unizip = 'uni-vga.tgz'

header = 'header.txt'
hex_name = 'univga_16.hex'

with tarfile.open(unizip, 'r:gz').extractfile(bdf_name) as infile:
    uni_vga = monobit.load(TextIOWrapper(infile), format='bdf')
    with open(hex_name, 'wb') as outfile:
        with open(header, 'rb') as h:
            for line in h:
                outfile.write(line)
        outfile.write(b'\n')
        uni_vga.save(outfile, format='hex')
Ejemplo n.º 3
0
    _name: _arg
    for _name, _arg in vars(args).items()
    if _arg is not None and _name in loader.script_args
}
save_args = {
    _name: _arg
    for _name, _arg in vars(args).items()
    if _arg is not None and _name in saver.script_args
}


if args.debug:
    loglevel = logging.DEBUG
else:
    loglevel = logging.INFO

logging.basicConfig(level=loglevel, format='%(levelname)s: %(message)s')

try:
    font = monobit.load(args.infile, format=args.from_, **load_args)
    if args.codepage:
        font = font.set_encoding(args.codepage)
    if args.comments:
        with open(args.comments) as f:
            font = font.add_comments(f.read())
    monobit.save(font, args.outfile, format=args.to_, **save_args)
except Exception as exc:
    logging.error(exc)
    if args.debug:
        raise
Ejemplo n.º 4
0
def main():

    # register custom FreeDOS codepages
    for filename in os.listdir(CODEPAGE_DIR):
        cp_name, ext = os.path.splitext(os.path.basename(filename))
        if ext == '.ucp':
            monobit.Codepage.override(f'cp{cp_name}', f'{os.getcwd()}/{CODEPAGE_DIR}/{filename}')

    try:
        os.mkdir('work')
    except OSError:
        pass
    try:
        os.mkdir('work/yaff')
    except OSError:
        pass

    # read header
    logging.info('Processing header')
    with open(HEADER, 'r') as header:
        comments = tuple(_line[2:].rstrip() for _line in header)

    # create empty fonts with header
    final_font = {
        size: monobit.font.Font(comments=comments).set_encoding('unicode')
        for size in SIZES
    }

    # obtain original source files
    os.chdir('work')
    logging.info('Downloading originals.')
    for source in (CPIDOS_URL, UNIVGA_URL, UNIFONT_URL):
        target = source.split('/')[-1]
        if not os.path.isfile(target):
            logging.info(f'Downloading {source}.')
            request.urlretrieve(source, target)

    # process unifont package
    with tarfile.open(UNIFONT_ZIP, 'r:gz') as unizip:
        for name in UNIFONT_NAMES:
            unizip.extract(UNIFONT_DIR + name)

    # process univga package
    with tarfile.open(UNIVGA_ZIP, 'r:gz') as univga:
        univga.extract(UNIVGA_BDF)

    # process CPIDOS package

    # unpack zipfile
    pack = zipfile.ZipFile(CPIDOS_ZIP, 'r')
    # extract cpi files from compressed cpx files
    for name in CPI_NAMES:
        pack.extract(CPI_DIR + name)
        subprocess.call(['upx', '-d', CPI_DIR + name])
    os.chdir('..')

    # load CPIs and add to dictionary
    freedos_fonts = {_size: {} for _size in SIZES}
    for cpi_name in CPI_NAMES:
        logging.info(f'Reading {cpi_name}')
        cpi = monobit.load(f'work/{CPI_DIR}{cpi_name}', format='cpi')
        for font in cpi:
            codepage = font.encoding # always starts with `cp`
            height = font.bounding_box[1]
            # save intermediate file
            monobit.save(
                font.add_glyph_names(),
                f'work/yaff/{cpi_name}_{codepage}_{font.pixel_size:02d}.yaff'
            )
            freedos_fonts[font.pixel_size][(cpi_name, codepage)] = font.set_encoding('unicode')

    # retrieve preferred picks from choices file
    logging.info('Processing choices')
    choices = defaultdict(list)
    with open(CHOICES, 'r') as f:
        for line in f:
            if line and line[0] in ('#', '\n'):
                continue
            codepoint, codepagestr = line.strip('\n').split(':', 1)
            codepage_info = codepagestr.split(':') # e.g. 852:ega.cpx
            if len(codepage_info) > 1:
                codepage, cpi_name = codepage_info[:2]
            else:
                codepage, cpi_name = codepage_info[0], None
            choices[(cpi_name, f'cp{codepage}')].append(chr(int(codepoint, 16)))

    # merge locally drawn glyphs
    for size in SIZES:
        for yaff in COMPONENTS[size]:
            logging.info(f'Merging {yaff}.')
            final_font[size] = final_font[size].merged_with(monobit.load(yaff))

    # merge preferred picks from FreeDOS fonts
    logging.info('Add freedos preferred glyphs')
    for size, fontdict in freedos_fonts.items():
        for (cpi_name_0, codepage_0), labels in choices.items():
            for (cpi_name_1, codepage_1), font in fontdict.items():
                if (
                        (codepage_0 == codepage_1)
                        and (cpi_name_0 is None or cpi_name_0 == cpi_name_1)
                    ):
                    final_font[size] = final_font[size].merged_with(font.subset(labels))

    # merge other fonts
    logging.info('Add remaining freedos glyphs')
    for size, fontdict in freedos_fonts.items():
        for font in fontdict.values():
            final_font[size] = final_font[size].merged_with(font)

    # assign length-1 equivalents
    logging.info('Assign canonical equivalents.')
    for size in final_font.keys():
        final_font[size] = precompose(final_font[size], max_glyphs=1)

    # drop glyphs with better alternatives in uni-vga
    final_font[16] = final_font[16].without(FREEDOS_DROP)

    # copy glyphs (canonical equivalents have been covered before)
    for size in final_font.keys():
        for copy, orig in FREEDOS_COPY.items():
            try:
                final_font[size] = final_font[size].with_glyph(
                    final_font[size].get_glyph(orig).set_annotations(char=copy)
                )
            except KeyError as e:
                logging.warning(e)
        for copy, orig in FREEDOS_MIRROR.items():
            try:
                orig = final_font[size].get_glyph(orig)
            except KeyError as e:
                logging.warning(e)
            else:
                offsets = orig.ink_offsets
                mirrored = orig.crop(*offsets).mirror().expand(*offsets)
                final_font[size] = final_font[size].with_glyph(mirrored.set_annotations(char=copy))
        for copy, orig in FREEDOS_FLIP.items():
            try:
                orig = final_font[size].get_glyph(orig)
            except KeyError as e:
                logging.warning(e)
            else:
                offsets = orig.ink_offsets
                flipped = orig.crop(*offsets).flip().expand(*offsets)
                final_font[size] = final_font[size].with_glyph(flipped.set_annotations(char=copy))
        for copy, orig in FREEDOS_TURN.items():
            try:
                orig = final_font[size].get_glyph(orig)
            except KeyError as e:
                logging.warning(e)
            else:
                offsets = orig.ink_offsets
                flipped = orig.crop(*offsets).flip().mirror().expand(*offsets)
                final_font[size] = final_font[size].with_glyph(flipped.set_annotations(char=copy))

    # read univga
    univga_orig = monobit.load(f'work/{UNIVGA_BDF}')
    # replace code points where necessary
    univga = univga_orig.without(UNIVGA_REPLACE.keys())
    for orig, repl in UNIVGA_REPLACE.items():
        univga = univga.with_glyph(univga_orig.get_glyph(orig).set_annotations(char=repl))

    # drop labels to avoid retaing chars on merge
    univga = monobit.Font(_g.set_annotations(labels=()) for _g in univga.glyphs)

    logging.info('Add uni-vga box-drawing glyphs.')
    box_glyphs = univga.subset(chr(_code) for _code in UNIVGA_UNSHIFTED)
    final_font[16] = final_font[16].merged_with(box_glyphs)

    # shift uni-vga baseline down by one
    logging.info('Add remaining uni-vga glyphs after rebaselining.')
    univga_rebaselined = univga.without(chr(_code) for _code in UNIVGA_NONPRINTING)
    univga_rebaselined = univga_rebaselined.expand(top=1).crop(bottom=1)
    final_font[16] = final_font[16].merged_with(univga_rebaselined)


    # copy glyphs from uni-vga
    for copy, orig in UNIVGA_COPY.items():
        final_font[16] = final_font[16].with_glyph(
            final_font[16].get_glyph(orig).set_annotations(char=copy)
        )

    # read unifont
    logging.info('Add glyphs from unifont.')
    unifont = monobit.Font().set_encoding('unicode')
    for name in UNIFONT_NAMES:
        unifont = unifont.merged_with(monobit.load(f'work/{UNIFONT_DIR}/{name}'))
    unifont_glyphs = unifont.subset(chr(_code) for _code in UNIFONT_RANGES)
    final_font[16] = final_font[16].merged_with(unifont_glyphs)


    # exclude personal use area code points
    logging.info('Removing private use area')
    pua_keys = set(chr(_code) for _code in range(0xe000, 0xf900))
    pua_font = {_size: _font.subset(pua_keys) for _size, _font in final_font.items()}
    for size, font in pua_font.items():
        monobit.save(font, f'work/pua_{size:02d}.hex', format='hext')
    final_font = {_size: _font.without(pua_keys) for _size, _font in final_font.items()}

    logging.info('Sorting glyphs')
    for size in final_font.keys():
        # first take the 437 subset
        # note this'll be the Freedos 437 as we overrode it
        keys437 = list(monobit.Codepage('cp437')._mapping.values())
        font437 = final_font[size].subset(keys437)
        sortedfont = monobit.font.Font(sorted(
            (_glyph for _glyph in final_font[size].glyphs),
            key=lambda _g: (_g.char or '')
        ))
        final_font[size] = font437.merged_with(sortedfont)

    # output
    logging.info('Writing output')
    for size, font in final_font.items():
        monobit.save(font.drop_comments(), f'{TARGET_DIR}/default_{size:02d}.hex', format='hext')

    #composed = {
    #    size: precompose(font, max_glyphs=4)
    #            .without(font.get_chars()).drop_comments().add_glyph_names()
    #    for size, font in final_font.items()
    #}

    #for size, font in composed.items():
    #    monobit.save(font, f'autocomposed_{size:02d}.yaff')

    for size, font in final_font.items():
        wrong_size = [f'{ord(g.char):04x}' for g in font.glyphs if g.height != size or g.width not in (8, 16)]
        if wrong_size:
            logging.warning(f'Wrong-size glyphs in {size}px font: {wrong_size}')