Skip to content
Snippets Groups Projects
update_icon_font.py 4.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/env python
    '''
    Updates icon font and header files for CopyQ repository.
    
    First argument is path to upacked Font Awesome archive (https://fontawesome.com/).
    '''
    import json
    import os
    import sys
    
    from shutil import copyfile
    
    hluk's avatar
    hluk committed
    from textwrap import dedent
    
    from fontTools.merge import Merger
    
    from fontTools.ttLib import TTFont
    
    FONTS = [
        'fa-solid-900.ttf',
        'fa-brands-400.ttf',
    
    FONT_FILENAME = 'fontawesome.ttf'
    
    SOLID_STYLE = 'solid'
    BRANDS_STYLE = 'brands'
    
    
    
    def read_icons(icons_json):
        with open(icons_json, 'r') as icons_file:
            icons_content = icons_file.read()
            return json.loads(icons_content)
    
    
    def write_header_file_preamble(header_file):
        script = os.path.realpath(__file__)
        script_name = os.path.basename(script)
        comment = (
                f'// This file is generated with "{script_name}"'
                + ' from FontAwesome\'s metadata.\n\n')
        header_file.write(comment)
    
    
    hluk's avatar
    hluk committed
    def write_icon_list_header_file(header_icon_list, icons):
        with open(header_icon_list, 'w') as header_file:
            items = []
    
            for style in [SOLID_STYLE, BRANDS_STYLE]:
                is_brand = 'true' if style == BRANDS_STYLE else 'false'
    
                for name, icon in icons.items():
                    if style in icon['styles']:
                        code = icon['unicode']
    
                        search_terms = [icon['label'].lower()] + (icon['search']['terms'] or [])
    
    hluk's avatar
    hluk committed
                        search_terms_list = '|'.join(search_terms)
                        items.append('{0x%s, %s, "%s"}' % (code, is_brand, search_terms_list))
    
            item_list_content = ',\n'.join(items)
            content = dedent('''\
                struct Icon {
                    unsigned int unicode;
                    bool isBrand;
                    const char *searchTerms;
                };
    
                constexpr Icon iconList[] = {
                %s
                };
            ''') % item_list_content
    
            write_header_file_preamble(header_file)
            header_file.write(content)
    
    
    
    def write_icons_header_file(header_icons, icons):
        with open(header_icons, 'w') as header_file:
            write_header_file_preamble(header_file)
            header_file.write('#ifndef ICONS_H\n')
            header_file.write('#define ICONS_H\n')
            header_file.write('\n')
            header_file.write('enum IconId {\n')
    
            for name, icon in icons.items():
                label = name.title().replace('-', '')
                code = icon['unicode']
                header_file.write(f'    Icon{label} = 0x{code},' + '\n')
    
            header_file.write('};\n')
            header_file.write('\n')
            header_file.write('#endif // ICONS_H\n')
    
    
    
    def rename_font_family(path):
        """
        Adds suffix to font family it doesn't conflict with font installed on
        system, which could be in incorrect version.
    
    hluk's avatar
    hluk committed
    
        See: https://github.com/fonttools/fonttools/blob/master/Snippets/rename-fonts.py
    
    hluk's avatar
    hluk committed
    
    
        font = TTFont(path)
        name_table = font['name']
    
    
    hluk's avatar
    hluk committed
        FAMILY_RELATED_IDS = dict(
            LEGACY_FAMILY=1,
            TRUETYPE_UNIQUE_ID=3,
            FULL_NAME=4,
            POSTSCRIPT_NAME=6,
            PREFERRED_FAMILY=16,
            WWS_FAMILY=21,
        )
    
        for rec in name_table.names:
            if rec.nameID not in FAMILY_RELATED_IDS.values():
                continue
    
    hluk's avatar
    hluk committed
            name = rec.toUnicode()
            if name.startswith('Font Awesome'):
                rec.string = name + ' (CopyQ)'
            elif name.startswith('FontAwesome'):
                rec.string = name + '(CopyQ)'
    
    hluk's avatar
    hluk committed
            assert rec.toUnicode().endswith('(CopyQ)')
    
    def copy_fonts(font_awesome_src, target_font_dir):
    
        font_dir = os.path.join(font_awesome_src, 'webfonts')
    
        fonts = [
            os.path.join(font_dir, src_name)
            for src_name in FONTS
        ]
        dest_path = os.path.join(target_font_dir, FONT_FILENAME)
    
        print(f'Merging fonts: {fonts} -> {dest_path}')
        merger = Merger()
        with merger.merge(fonts) as font:
            font.save(dest_path)
    
        rename_font_family(dest_path)
    
    
    
    def main():
        font_awesome_src = sys.argv[1]
    
        script = os.path.realpath(__file__)
        utils_dir = os.path.dirname(script)
    
    hluk's avatar
    hluk committed
        project_dir = os.path.dirname(utils_dir)
        src_dir = os.path.join(project_dir, 'src')
    
    hluk's avatar
    hluk committed
        header_icon_list = os.path.join(src_dir, 'gui', 'icon_list.h')
    
        header_icons = os.path.join(src_dir, 'gui', 'icons.h')
    
        target_font_dir = os.path.join(src_dir, 'images')
        copy_fonts(font_awesome_src, target_font_dir)
    
        icons_json = os.path.join(
    
                font_awesome_src, 'metadata', 'icons.json')
    
        icons = read_icons(icons_json)
    
    
    hluk's avatar
    hluk committed
        write_icon_list_header_file(header_icon_list, icons)
        print(f'Header file "{header_icon_list}" updated.')
    
    
        write_icons_header_file(header_icons, icons)
        print(f'Header file "{header_icons}" updated.')
    
    
    if __name__ == '__main__':
        main()