2024-09-28 10:31:06 -07:00
# Convert Font Awesome, Fork Awesome, Google Material Design, Pictogrammers Material Design Icons, Kenney Game,
# Fontaudio, Codicons and Lucide icon font parameters to C, C++, C#, Python, Rust and Go compatible formats.
2024-03-23 18:41:26 -07:00
#
#------------------------------------------------------------------------------
#
# 1 - Source material
#
2024-09-28 10:31:06 -07:00
# 1.1 - Font Awesome [ FA ]
# https://fontawesome.com
# https://github.com/FortAwesome/Font-Awesome
2024-03-23 18:41:26 -07:00
#
# 1.1.1 - version 4
2024-09-28 10:31:06 -07:00
# https://github.com/FortAwesome/Font-Awesome/tree/4.x
2024-03-23 18:41:26 -07:00
# https://github.com/FortAwesome/Font-Awesome/blob/4.x/src/icons.yml
# https://github.com/FortAwesome/Font-Awesome/blob/4.x/fonts/fontawesome-webfont.ttf
#
# 1.1.2 - version 5 Free
2024-09-28 10:31:06 -07:00
# https://github.com/FortAwesome/Font-Awesome/tree/5.x
2024-03-23 18:41:26 -07:00
# https://github.com/FortAwesome/Font-Awesome/blob/5.x/metadata/icons.yml
2024-09-28 10:31:06 -07:00
# https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-brands-400.ttf [ FAB ]
# https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-regular-400.ttf [ FAR ]
# https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-solid-900.ttf [ FAS ]
2024-03-23 18:41:26 -07:00
#
# 1.1.3 - version 5 Pro
# Download files from https://fontawesome.com
# \fontawesome-pro-n.n.n-web\metadata\icons.yml
2024-09-28 10:31:06 -07:00
# \fontawesome-pro-n.n.n-web\webfonts\fa-brands-400.ttf [ FAB ]
# \fontawesome-pro-n.n.n-web\webfonts\fa-light-300.ttf [ FAL ]
# \fontawesome-pro-n.n.n-web\webfonts\fa-regular-400.ttf [ FAR ]
# \fontawesome-pro-n.n.n-web\webfonts\fa-solid-900.ttf [ FAS ]
2024-03-23 18:41:26 -07:00
#
# 1.1.4 - version 6 Free
2024-09-28 10:31:06 -07:00
# https://github.com/FortAwesome/Font-Awesome/tree/6.x
2024-03-23 18:41:26 -07:00
# https://github.com/FortAwesome/Font-Awesome/blob/6.x/metadata/icons.yml
2024-09-28 10:31:06 -07:00
# https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-brands-400.ttf [ FAB ]
# https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-regular-400.ttf [ FAR ]
# https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-solid-900.ttf [ FAS ]
2024-03-23 18:41:26 -07:00
#
2024-09-28 10:31:06 -07:00
# 1.2 - Fork Awesome [ FK ]
# https://forkaweso.me/Fork-Awesome/
# https://github.com/ForkAwesome/Fork-Awesome
2024-03-23 18:41:26 -07:00
# https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/icons.yml
# https://github.com/ForkAwesome/Fork-Awesome/blob/master/fonts/forkawesome-webfont.ttf
#
2024-09-28 10:31:06 -07:00
# 1.3 - Google Material Design Icons [ MD ] and Material Symbols [ MS ]
# https://fonts.google.com/icons
# https://github.com/google/material-design-icons
#
# 1.3.1 - Material Design Icons [ MD ]
# https://fonts.google.com/icons?icon.set=Material+Icons
2024-03-23 18:41:26 -07:00
# https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.codepoints
# https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf
#
2024-09-28 10:31:06 -07:00
# 1.3.2 - Material Symbols [ MS ]
# https://fonts.google.com/icons?icon.set=Material+Symbols
# https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsOutlined%5BFILL%2CGRAD%2Copsz%2Cwght%5D.codepoints
# https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsOutlined%5BFILL,GRAD,opsz,wght%5D.ttf [ MSO ]
# https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf [ MSR ]
# https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsSharp[FILL,GRAD,opsz,wght].ttf [ MSS ]
#
# 1.4 - Pictogrammers Material Design Icons [ MDI ]
# https://pictogrammers.com/library/mdi/
# https://github.com/Templarian/MaterialDesign-Webfont
# https://github.com/Templarian/MaterialDesign-Webfont/blob/master/css/materialdesignicons.css
# https://github.com/Templarian/MaterialDesign-Webfont/blob/master/fonts/materialdesignicons-webfont.ttf
#
# 1.5 - Kenney Game Icons and Expansion [ KI ]
# http://kenney.nl/assets/game-icons http://kenney.nl/assets/game-icons-expansion
# https://github.com/nicodinh/kenney-icon-font
2024-03-23 18:41:26 -07:00
# https://github.com/nicodinh/kenney-icon-font/blob/master/css/kenney-icons.css
# https://github.com/nicodinh/kenney-icon-font/blob/master/fonts/kenney-icon-font.ttf
#
2024-09-28 10:31:06 -07:00
# 1.6 - Fontaudio [ FAD ]
# https://github.com/fefanto/fontaudio
2024-03-23 18:41:26 -07:00
# https://github.com/fefanto/fontaudio/blob/master/font/fontaudio.css
# https://github.com/fefanto/fontaudio/blob/master/font/fontaudio.ttf
#
2024-09-28 10:31:06 -07:00
# 1.7 - Codicons [ CI ]
# https://microsoft.github.io/vscode-codicons/dist/codicon.html
# https://github.com/microsoft/vscode-codicons
# https://microsoft.github.io/vscode-codicons/dist/codicon.css
# https://microsoft.github.io/vscode-codicons/dist/codicon.ttf
#
# 1.8 - Lucide [ LC ]
# https://lucide.dev
# https://github.com/lucide-icons/lucide
# https://unpkg.com/lucide-static@latest/font/lucide.css
# https://unpkg.com/lucide-static@latest/font/lucide.ttf
#
2024-03-23 18:41:26 -07:00
#
#------------------------------------------------------------------------------
#
# 2 - Data sample
#
# Font Awesome 4 example:
#
# - input: music:
# changes:
# - '1'
# - 5.0.0
# label: Music
# search:
# terms:
# - note
# - sound
# styles:
# - solid
# unicode: f001
#
# - output C and C++: #define ICON_FA_MUSIC "\xef\x80\x81" // U+f001
# - output C#: public const string Music = "\uf001";
# - output Python: ICON_MUSIC = '\uf001'
# - output Rust: pub const ICON_MUSIC: char = '\u{f001}';
# - output Go: "Music": "\xef\x80\x81", // U+f001
#
# All fonts have computed min, max_16 and max unicode fonts.
# The min excludes the ASCII characters code points.
# The max_16 is for use with libraries that only support 16 bit code points.
#
# - output C and C++: #define ICON_MIN_FA 0xf000
# #define ICON_MAX_16_FA 0xf2e0
# #define ICON_MAX_FA 0xf2e0
# Exception for Font Awesome brands: we use ICON_MIN_FAB, ICON_MAX_16_FAB and ICON_MAX_FAB
# to differentiate between brand and non-brand icons so they can be used together
# (the defines must be unique in C and C++).
#
# - output C#: public const int IconMin = 0xf000;
# public const int IconMax16 = 0xf2e0;
# public const int IconMax = 0xf2e0;
#
# - output Python: ICON_MIN = 0xf000
# ICON_MAX_16 = 0xf2e0
# ICON_MAX = 0xf2e0
#
# - output Rust: pub const ICON_MIN: char = '\u{f000}';
# pub const ICON_MAX_16: char = '\u{f2e0}';
# pub const ICON_MAX: char = '\u{f2e0}';
#
# - output Go: Min: 0xf000,
# Max16: 0xf2e0,
# Max: 0xf2e0,
#
#------------------------------------------------------------------------------
#
# 3 - Script dependencies
#
# 3.1 - Fonts source material online
# 3.2 - Python 3 - https://www.python.org/downloads/
# 3.3 - Requests - https://pypi.org/project/requests/
# 3.4 - PyYAML - https://pypi.org/project/PyYAML/
#
#------------------------------------------------------------------------------
#
# 4 - References
#
# GitHub repository: https://github.com/juliettef/IconFontCppHeaders/
#
#------------------------------------------------------------------------------
import requests
import yaml
import os
import sys
import logging
if sys . version_info [ 0 ] < 3 :
raise Exception ( " Python 3 or a more recent version is required. " )
# Fonts
class Font :
font_name = ' [ ERROR - Missing font name ] '
font_abbr = ' [ ERROR - Mssing font abbreviation ] '
font_minmax_abbr = ' ' # optional - use if min and max defines must be differentiated. See Font Awesome Brand for example.
font_data = ' [ ERROR - Missing font data file or url ] '
ttfs = ' [ ERROR - Missing ttf ] '
@classmethod
def get_icons ( cls , input_data ) :
# intermediate representation of the fonts data, identify the min and max
logging . error ( ' Missing implementation of class method get_icons for {!s} ] ' . format ( cls . font_name ) )
icons_data = { }
icons_data . update ( { ' font_min ' : ' [ ERROR - Missing font min ] ' ,
' font_max ' : ' [ ERROR - Missing font max ] ' ,
' icons ' : ' [ ERROR - Missing list of pairs [ font icon name, code ]] ' } )
return icons_data
@classmethod
def get_intermediate_representation ( cls ) :
font_ir = { }
if ' http ' in cls . font_data : # if url, download data
response = requests . get ( cls . font_data , timeout = 2 )
if response . status_code == 200 :
input_raw = response . text
logging . info ( ' Downloaded - ' + cls . font_name )
else :
raise Exception ( ' Download failed - ' + cls . font_name )
else : # read data from file if present
if os . path . isfile ( cls . font_data ) :
with open ( cls . font_data , ' r ' ) as f :
input_raw = f . read ( )
f . close ( )
logging . info ( ' File read - ' + cls . font_name )
else :
raise Exception ( ' File ' + cls . font_name + ' missing - ' + cls . font_data )
if input_raw :
icons_data = cls . get_icons ( input_raw )
font_ir . update ( icons_data )
font_ir . update ( { ' font_data ' : cls . font_data ,
' font_name ' : cls . font_name ,
' font_abbr ' : cls . font_abbr ,
' font_minmax_abbr ' : cls . font_minmax_abbr ,
' ttfs ' : cls . ttfs , } )
logging . info ( ' Generated intermediate data - ' + cls . font_name )
return font_ir
class FontFA4 ( Font ) : # legacy Font Awesome version 4
font_name = ' Font Awesome 4 '
font_abbr = ' FA '
font_data = ' https://github.com/FortAwesome/Font-Awesome/raw/4.x/src/icons.yml '
ttfs = [ [ font_abbr , ' fontawesome-webfont.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/4.x/fonts/fontawesome-webfont.ttf ' ] ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
data = yaml . safe_load ( input_data )
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for item in data [ ' icons ' ] :
item_unicode = item [ ' unicode ' ] . zfill ( 4 )
item_int = int ( item_unicode , 16 )
if item_int < font_min_int and item_int > 0x0127 : # exclude ASCII characters code points
font_min = item_unicode
font_min_int = item_int
if item_int > font_max_16_int and item_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = item_unicode
font_max_16_int = item_int
if item_int > font_max_int :
font_max = item_unicode
font_max_int = item_int
icons . append ( [ item [ ' id ' ] , item_unicode ] )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
class FontFK ( FontFA4 ) : # Fork Awesome, based on Font Awesome 4
font_name = ' Fork Awesome '
font_abbr = ' FK '
font_data = ' https://github.com/ForkAwesome/Fork-Awesome/raw/master/src/icons/icons.yml '
ttfs = [ [ font_abbr , ' forkawesome-webfont.ttf ' , ' https://github.com/ForkAwesome/Fork-Awesome/blob/master/fonts/forkawesome-webfont.ttf ' ] ]
class FontFA5 ( Font ) : # Font Awesome version 5 - Regular and Solid styles
font_name = ' Font Awesome 5 '
font_abbr = ' FA '
font_data = ' https://github.com/FortAwesome/Font-Awesome/raw/5.x/metadata/icons.yml '
ttfs = [ [ ' FAR ' , ' fa-regular-400.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-regular-400.ttf ' ] ,
[ ' FAS ' , ' fa-solid-900.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-solid-900.ttf ' ] ]
font_fa_style = [ ' regular ' , ' solid ' ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
data = yaml . safe_load ( input_data )
if data :
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for key in data :
item = data [ key ]
for style in item [ ' styles ' ] :
if style in cls . font_fa_style :
item_unicode = item [ ' unicode ' ] . zfill ( 4 )
if [ key , item_unicode ] not in icons :
item_int = int ( item_unicode , 16 )
if item_int < font_min_int and item_int > 0x0127 : # exclude ASCII characters code points
font_min = item_unicode
font_min_int = item_int
if item_int > font_max_16_int and item_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = item_unicode
font_max_16_int = item_int
if item_int > font_max_int :
font_max = item_unicode
font_max_int = item_int
icons . append ( [ key , item_unicode ] )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
class FontFA5Brands ( FontFA5 ) : # Font Awesome version 5 - Brand style
font_name = ' Font Awesome 5 Brands '
font_minmax_abbr = ' FAB '
ttfs = [ [ ' FAB ' , ' fa-brands-400.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-brands-400.ttf ' ] ]
font_fa_style = [ ' brands ' ]
class FontFA5Pro ( FontFA5 ) : # Font Awesome version 5 Pro - Light, Regular and Solid styles
font_name = ' Font Awesome 5 Pro '
font_data = ' icons.yml '
ttfs = [ [ ' FAL ' , ' fa-light-300.ttf ' , ' fa-light-300.ttf ' ] ,
[ ' FAR ' , ' fa-regular-400.ttf ' , ' fa-regular-400.ttf ' ] ,
[ ' FAS ' , ' fa-solid-900.ttf ' , ' fa-solid-900.ttf ' ] ]
font_fa_style = [ ' light ' , ' regular ' , ' solid ' ]
class FontFA5ProBrands ( FontFA5Brands ) : # Font Awesome version 5 Pro - Brand style
font_name = ' Font Awesome 5 Pro Brands '
font_data = ' icons.yml '
ttfs = [ [ ' FAB ' , ' fa-brands-400.ttf ' , ' fa-brands-400.ttf ' ] ]
class FontFA6 ( FontFA5 ) : # Font Awesome version 6 - Regular and Solid styles
font_name = ' Font Awesome 6 '
font_data = ' https://github.com/FortAwesome/Font-Awesome/raw/6.x/metadata/icons.yml '
ttfs = [ [ ' FAR ' , ' fa-regular-400.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-regular-400.ttf ' ] ,
[ ' FAS ' , ' fa-solid-900.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-solid-900.ttf ' ] ]
class FontFA6Brands ( FontFA5Brands ) : # Font Awesome version 6 - Brand style
font_name = ' Font Awesome 6 Brands '
font_data = ' https://github.com/FortAwesome/Font-Awesome/raw/6.x/metadata/icons.yml '
ttfs = [ [ ' FAB ' , ' fa-brands-400.ttf ' , ' https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-brands-400.ttf ' ] ]
2024-09-28 10:31:06 -07:00
class FontMD ( Font ) : # Google Material Design
2024-03-23 18:41:26 -07:00
font_name = ' Material Design '
font_abbr = ' MD '
font_data = ' https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.codepoints '
ttfs = [ [ font_abbr , ' MaterialIcons-Regular.ttf ' , ' https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf ' ] ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
lines = str . split ( input_data , ' \n ' )
if lines :
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for line in lines :
if line == ' flourescent ec31 ' : # Issue #27 workaround: exclude duplicate Material Design 'flourescent ec31'. https://github.com/juliettef/IconFontCppHeaders/issues/27
logging . warning ( " Issue #27 workaround: exclude duplicate Material Design ' flourescent ec31 ' . https://github.com/juliettef/IconFontCppHeaders/issues/27 " )
else :
words = str . split ( line )
if words and len ( words ) > = 2 :
word_unicode = words [ 1 ] . zfill ( 4 )
word_int = int ( word_unicode , 16 )
if word_int < font_min_int and word_int > 0x0127 : # exclude ASCII characters code points
font_min = word_unicode
font_min_int = word_int
if word_int > font_max_16_int and word_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = word_unicode
font_max_16_int = word_int
if word_int > font_max_int :
font_max = word_unicode
font_max_int = word_int
icons . append ( words )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
2024-09-28 10:31:06 -07:00
class FontMS ( Font ) : # Google Material Symbols
font_name = ' Material Symbols '
font_abbr = ' MS '
font_data = ' https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsOutlined % 5BFILL % 2CGRAD % 2Copsz % 2Cwght % 5D.codepoints '
ttfs = [ [ ' MSO ' , ' MaterialSymbolsOutlined[FILL,GRAD,opsz,wght].ttf ' , ' https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsOutlined % 5BFILL,GRAD,opsz,wght % 5D.ttf ' ] ,
[ ' MSR ' , ' MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf ' , ' https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsRounded % 5BFILL,GRAD,opsz,wght % 5D.ttf ' ] ,
[ ' MSS ' , ' MaterialSymbolsSharp[FILL,GRAD,opsz,wght].ttf ' , ' https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsSharp % 5BFILL,GRAD,opsz,wght % 5D.ttf ' ] ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
lines = str . split ( input_data , ' \n ' )
if lines :
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for line in lines :
words = str . split ( line )
if words and len ( words ) > = 2 :
word_unicode = words [ 1 ] . zfill ( 4 )
word_int = int ( word_unicode , 16 )
if word_int < font_min_int and word_int > 0x0127 : # exclude ASCII characters code points
font_min = word_unicode
font_min_int = word_int
if word_int > font_max_16_int and word_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = word_unicode
font_max_16_int = word_int
if word_int > font_max_int :
font_max = word_unicode
font_max_int = word_int
icons . append ( words )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
class FontMDI ( Font ) : # Pictogrammers Material Design Icons
font_name = ' Material Design Icons '
font_abbr = ' MDI '
font_data_prefix = ' .mdi- '
font_data = ' https://github.com/Templarian/MaterialDesign-Webfont/raw/master/css/materialdesignicons.css '
ttfs = [ [ font_abbr , ' materialdesignicons-webfont.ttf ' , ' https://github.com/Templarian/MaterialDesign-Webfont/raw/master/fonts/materialdesignicons-webfont.ttf ' ] ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
lines = str . split ( input_data , ' } \n ' )
if lines :
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for line in lines :
if cls . font_data_prefix in line and ' ::before ' in line :
font_id = line . partition ( cls . font_data_prefix ) [ 2 ] . partition ( ' ::before ' ) [ 0 ]
font_code = line . partition ( ' " \\ ' ) [ 2 ] . partition ( ' " ' ) [ 0 ] . zfill ( 4 )
font_code_int = int ( font_code , 16 )
if font_code_int < font_min_int and font_code_int > 0x0127 : # exclude ASCII characters code points
font_min = font_code
font_min_int = font_code_int
if font_code_int > font_max_16_int and font_code_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = font_code
font_max_16_int = font_code_int
if font_code_int > font_max_int :
font_max = font_code
font_max_int = font_code_int
icons . append ( [ font_id , font_code ] )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
2024-03-23 18:41:26 -07:00
class FontKI ( Font ) : # Kenney Game icons
font_name = ' Kenney '
font_abbr = ' KI '
font_data_prefix = ' .ki- '
font_data = ' https://github.com/nicodinh/kenney-icon-font/raw/master/css/kenney-icons.css '
ttfs = [ [ font_abbr , ' kenney-icon-font.ttf ' , ' https://github.com/nicodinh/kenney-icon-font/blob/master/fonts/kenney-icon-font.ttf ' ] ]
@classmethod
def get_icons ( cls , input_data ) :
icons_data = { }
lines = str . split ( input_data , ' } \n ' )
if lines :
font_min = ' 0x10ffff '
font_min_int = int ( font_min , 16 )
font_max_16 = ' 0x0 ' # 16 bit max
font_max_16_int = int ( font_max_16 , 16 )
font_max = ' 0x0 '
font_max_int = int ( font_max , 16 )
icons = [ ]
for line in lines :
if cls . font_data_prefix in line and ' :before ' in line :
font_id = line . partition ( cls . font_data_prefix ) [ 2 ] . partition ( ' :before ' ) [ 0 ]
font_code = line . partition ( ' " \\ ' ) [ 2 ] . partition ( ' " ' ) [ 0 ] . zfill ( 4 )
font_code_int = int ( font_code , 16 )
if font_code_int < font_min_int and font_code_int > 0x0127 : # exclude ASCII characters code points
font_min = font_code
font_min_int = font_code_int
if font_code_int > font_max_16_int and font_code_int < = 0xffff : # exclude code points > 16 bits
font_max_16 = font_code
font_max_16_int = font_code_int
if font_code_int > font_max_int :
font_max = font_code
font_max_int = font_code_int
icons . append ( [ font_id , font_code ] )
icons_data . update ( { ' font_min ' : font_min ,
' font_max_16 ' : font_max_16 ,
' font_max ' : font_max ,
' icons ' : icons } )
return icons_data
class FontFAD ( FontKI ) : # Fontaudio
font_name = ' Fontaudio '
font_abbr = ' FAD '
font_data_prefix = ' .icon-fad- '
font_data = ' https://github.com/fefanto/fontaudio/raw/master/font/fontaudio.css '
ttfs = [ [ font_abbr , ' fontaudio.ttf ' , ' https://github.com/fefanto/fontaudio/blob/master/font/fontaudio.ttf ' ] ]
class FontCI ( FontKI ) : # Codicons
font_name = ' Codicons '
font_abbr = ' CI '
font_data_prefix = ' .codicon- '
2024-09-28 10:31:06 -07:00
font_data = ' https://microsoft.github.io/vscode-codicons/dist/codicon.css '
ttfs = [ [ font_abbr , ' codicon.ttf ' , ' https://microsoft.github.io/vscode-codicons/dist/codicon.ttf ' ] ]
class FontLC ( FontKI ) : # Lucide
font_name = ' Lucide '
font_abbr = ' LC '
font_data_prefix = ' .icon- '
font_data = ' https://unpkg.com/lucide-static@latest/font/lucide.css ' # alt 'https://cdn.jsdelivr.net/npm/lucide-static@latest/font/lucide.css'
ttfs = [ [ font_abbr , ' lucide.ttf ' , ' https://unpkg.com/lucide-static@latest/font/lucide.ttf ' ] ] # alt 'https://cdn.jsdelivr.net/npm/lucide-static@latest/font/lucide.ttf'
2024-03-23 18:41:26 -07:00
# Languages
class Language :
language_name = ' [ ERROR - Missing language name ] '
file_name = ' [ ERROR - Missing file name ] '
intermediate = { }
def __init__ ( self , intermediate ) :
self . intermediate = intermediate
@classmethod
def prelude ( cls ) :
logging . error ( ' Missing implementation of class method prelude for {!s} ' . format ( cls . language_name ) )
return ' '
@classmethod
def line_icon ( cls , icon ) :
logging . error ( ' Missing implementation of class method line_icon for {!s} ' . format ( cls . language_name ) )
return ' '
@classmethod
def epilogue ( cls ) :
return ' '
@classmethod
def convert ( cls ) :
result = cls . prelude ( )
for icon in cls . intermediate . get ( ' icons ' ) :
line_icon = cls . line_icon ( icon )
result + = line_icon
result + = cls . epilogue ( )
logging . info ( ' Converted - {!s} for {!s} ' . format ( cls . intermediate . get ( ' font_name ' ) , cls . language_name ) )
return result
@classmethod
def save_to_file ( cls ) :
filename = cls . file_name . format ( name = str ( cls . intermediate . get ( ' font_name ' ) ) . replace ( ' ' , ' ' ) )
converted = cls . convert ( )
with open ( filename , ' w ' ) as f :
f . write ( converted )
f . close ( )
logging . info ( ' Saved - {!s} ' . format ( filename ) )
class LanguageC ( Language ) :
language_name = ' C and C++ '
file_name = ' Icons {name} .h '
@classmethod
def prelude ( cls ) :
2024-09-28 10:31:06 -07:00
tmpl_prelude = ' // Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' // for {lang} \n ' + \
' // from codepoints {font_data} \n ' + \
' // for use with font {ttf_files} \n \n ' + \
2024-03-23 18:41:26 -07:00
' #pragma once \n \n '
ttf_files = [ ]
for ttf in cls . intermediate . get ( ' ttfs ' ) :
ttf_files . append ( ttf [ 2 ] )
result = tmpl_prelude . format ( lang = cls . language_name ,
font_data = cls . intermediate . get ( ' font_data ' ) ,
ttf_files = ' , ' . join ( ttf_files ) )
tmpl_prelude_define_file_name = ' #define FONT_ICON_FILE_NAME_ {font_abbr} " {file_name_ttf} " \n '
for ttf in cls . intermediate . get ( ' ttfs ' ) :
result + = tmpl_prelude_define_file_name . format ( font_abbr = ttf [ 0 ] , file_name_ttf = ttf [ 1 ] )
result + = ' \n '
# min/max
tmpl_line_minmax = ' #define ICON_ {minmax} _ {abbr} 0x {val} \n '
abbreviation = cls . intermediate . get ( ' font_minmax_abbr ' ) if cls . intermediate . get ( ' font_minmax_abbr ' ) else cls . intermediate . get ( ' font_abbr ' )
result + = tmpl_line_minmax . format ( minmax = ' MIN ' ,
abbr = abbreviation ,
val = cls . intermediate . get ( ' font_min ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX_16 ' ,
abbr = abbreviation ,
val = cls . intermediate . get ( ' font_max_16 ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX ' ,
abbr = abbreviation ,
2024-09-28 10:31:06 -07:00
val = cls . intermediate . get ( ' font_max ' ) ) + ' \n '
2024-03-23 18:41:26 -07:00
return result
@classmethod
def line_icon ( cls , icon ) :
tmpl_line_icon = ' #define ICON_ {abbr} _ {icon} " {code} " \t // U+ {unicode} \n '
icon_name = str . upper ( icon [ 0 ] ) . replace ( ' - ' , ' _ ' )
icon_code = repr ( chr ( int ( icon [ 1 ] , 16 ) ) . encode ( ' utf-8 ' ) ) [ 2 : - 1 ]
result = tmpl_line_icon . format ( abbr = cls . intermediate . get ( ' font_abbr ' ) ,
icon = icon_name ,
code = icon_code ,
unicode = icon [ 1 ] )
return result
@classmethod
def convert_ttf_to_header ( cls ) :
for ttf in cls . intermediate . get ( ' ttfs ' ) :
# retrieve and read ttf file
if ' http ' in ttf [ 2 ] :
# download and read (if file is on GitHub, add '?raw=true')
response = requests . get ( ttf [ 2 ] + ' ?raw=true ' if ' github.com ' in ttf [ 2 ] else ttf [ 2 ] , timeout = 2 )
if response . status_code == 200 :
ttf_data = response . content
logging . info ( ' ttf file downloaded - ' + ttf [ 1 ] )
else :
raise Exception ( ' ttf file missing - ' + ttf [ 2 ] )
else :
# open from disk and read
if os . path . isfile ( ttf [ 2 ] ) :
with open ( ttf [ 2 ] , ' rb ' ) as f :
ttf_data = f . read ( )
f . close ( )
logging . info ( ' ttf file read - ' + ttf [ 1 ] )
else :
raise Exception ( ' ttf file missing - ' + ttf [ 2 ] )
# convert to header and save to disk
if ttf_data :
# convert ttf to header
2024-09-28 10:31:06 -07:00
tmpl_prelude_ttf = ' // Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' // for {lang} \n ' + \
' // from font {ttf_file} \n ' + \
' // Requires #include <stdint.h> \n \n ' + \
2024-03-23 18:41:26 -07:00
' #pragma once \n \n ' + \
' static const uint8_t s_ {name} _ttf[ {size} ] = \n {{ '
result = tmpl_prelude_ttf . format ( lang = cls . language_name ,
ttf_file = ttf [ 2 ] ,
name = str ( ttf [ 1 ] [ : - len ( ' .ttf ' ) ] . replace ( ' - ' , ' _ ' ) . replace ( ' ' , ' ' ) ) ,
size = str ( len ( ttf_data ) ) )
n = 0
for byte in ttf_data :
if ( n % 16 ) == 0 :
result + = ' \n \t '
result + = " 0x " + str ( hex ( int ( byte / 16 ) ) [ 2 : ] ) + str ( hex ( byte % 16 ) [ 2 : ] ) + " , "
n + = 1
result + = ' \n }; \n \n '
# save to disk
ttf_header_file_name = cls . file_name . format ( name = str ( cls . intermediate . get ( ' font_name ' ) ) . replace ( ' ' , ' ' ) ) + ' _ ' + ttf [ 1 ] + ' .h '
with open ( ttf_header_file_name , ' w ' ) as f :
f . write ( result )
f . close ( )
logging . info ( ' ttf File Saved - {!s} ' . format ( ttf_header_file_name ) )
else :
raise Exception ( ' Failed ttf to header conversion ' + ttf [ 1 ] )
class LanguageCSharp ( Language ) :
language_name = " C# "
file_name = ' Icons {name} .cs '
@classmethod
def prelude ( cls ) :
2024-09-28 10:31:06 -07:00
tmpl_prelude = \
' // <auto-generated> \n ' + \
' // Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' // for {lang} \n ' + \
' // from codepoints {font_data} \n ' + \
' // for use with font {ttf_files} \n ' + \
' // </auto-generated> \n \n ' + \
2024-03-23 18:41:26 -07:00
' namespace IconFonts \n ' + \
' {{ \n ' + \
' public class {font_name} \n ' + \
' {{ \n '
ttf_files = [ ]
for ttf in cls . intermediate . get ( ' ttfs ' ) :
ttf_files . append ( ttf [ 2 ] )
result = tmpl_prelude . format ( lang = cls . language_name ,
font_data = cls . intermediate . get ( ' font_data ' ) ,
ttf_files = ' , ' . join ( ttf_files ) ,
font_name = cls . intermediate . get ( ' font_name ' ) . replace ( ' ' , ' ' ) )
tmpl_prelude_define_file_name = ' public const string FontIconFileName {font_abbr} = " {file_name_ttf} " ; \n '
for ttf in cls . intermediate . get ( ' ttfs ' ) :
result + = tmpl_prelude_define_file_name . format ( font_abbr = ttf [ 0 ] , file_name_ttf = ttf [ 1 ] )
result + = ' \n '
# min/max
tmpl_line_minmax = ' public const int Icon {minmax} = 0x {val} ; \n '
result + = tmpl_line_minmax . format ( minmax = ' Min ' ,
val = cls . intermediate . get ( ' font_min ' ) ) + \
tmpl_line_minmax . format ( minmax = ' Max16 ' ,
val = cls . intermediate . get ( ' font_max_16 ' ) ) + \
tmpl_line_minmax . format ( minmax = ' Max ' ,
2024-09-28 10:31:06 -07:00
val = cls . intermediate . get ( ' font_max ' ) ) + ' \n '
2024-03-23 18:41:26 -07:00
return result
@classmethod
def epilogue ( cls ) :
return ' } \n ' + \
' } \n '
@classmethod
def line_icon ( cls , icon ) :
2024-09-28 10:31:06 -07:00
tmpl_line_icon = ' public const string {icon} = {literal} ; \n '
2024-03-23 18:41:26 -07:00
icon_name = cls . to_camelcase ( icon [ 0 ] )
icon_code = icon [ 1 ]
if icon_name [ 0 ] . isdigit ( ) :
# Variable may not start with a digit
icon_name = ' Num ' + icon_name
if icon_name == cls . intermediate . get ( ' font_name ' ) . replace ( ' ' , ' ' ) :
# Member may not have same name as enclosing class
icon_name + = ' Icon '
2024-09-28 10:31:06 -07:00
# "\u1234"
if len ( icon_code ) < = 4 :
literal = ' " \\ u {code} " ' . format ( code = icon_code . rjust ( 4 , ' 0 ' ) )
# "\U12345678"
else :
literal = ' " \\ U {code} " ' . format ( code = icon_code . rjust ( 8 , ' 0 ' ) )
result = tmpl_line_icon . format ( icon = icon_name , literal = literal )
2024-03-23 18:41:26 -07:00
return result
@classmethod
def to_camelcase ( cls , text ) :
parts = text . split ( ' - ' )
for i in range ( len ( parts ) ) :
p = parts [ i ]
parts [ i ] = p [ 0 ] . upper ( ) + p [ 1 : ] . lower ( )
return ' ' . join ( parts )
class LanguagePython ( Language ) :
language_name = " Python "
file_name = ' Icons {name} .py '
@classmethod
def prelude ( cls ) :
2024-09-28 10:31:06 -07:00
tmpl_prelude = ' # Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' # for {lang} \n ' + \
' # from codepoints {font_data} \n ' + \
' # for use with font {ttf_files} \n \n ' + \
' class Icons {font_name} : \n \n '
2024-03-23 18:41:26 -07:00
ttf_files = [ ]
for ttf in cls . intermediate . get ( ' ttfs ' ) :
ttf_files . append ( ttf [ 2 ] )
result = tmpl_prelude . format ( lang = cls . language_name ,
font_data = cls . intermediate . get ( ' font_data ' ) ,
ttf_files = ' , ' . join ( ttf_files ) ,
font_name = cls . intermediate . get ( ' font_name ' ) . replace ( ' ' , ' ' ) )
tmpl_prelude_define_file_name = " FONT_ICON_FILE_NAME_ {font_abbr} = ' {file_name_ttf} ' \n "
for ttf in cls . intermediate . get ( ' ttfs ' ) :
result + = tmpl_prelude_define_file_name . format ( font_abbr = ttf [ 0 ] , file_name_ttf = ttf [ 1 ] )
result + = ' \n '
# min/max
tmpl_line_minmax = ' ICON_ {minmax} = 0x {val} \n '
result + = t mpl_line_minmax . format ( minmax = ' MIN ' ,
val = cls . intermediate . get ( ' font_min ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX_16 ' ,
val = cls . intermediate . get ( ' font_max_16 ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX ' ,
2024-09-28 10:31:06 -07:00
val = cls . intermediate . get ( ' font_max ' ) ) + ' \n '
2024-03-23 18:41:26 -07:00
return result
@classmethod
def line_icon ( cls , icon ) :
tmpl_line_icon = " ICON_ {icon} = ' \\ u {code} ' \n "
icon_name = str . upper ( icon [ 0 ] ) . replace ( ' - ' , ' _ ' )
icon_code = icon [ 1 ]
result = tmpl_line_icon . format ( icon = icon_name , code = icon_code )
return result
2024-09-28 10:31:06 -07:00
2024-03-23 18:41:26 -07:00
class LanguageRust ( Language ) :
language_name = " Rust "
file_name = ' Icons {name} .rs '
@classmethod
def prelude ( cls ) :
2024-09-28 10:31:06 -07:00
tmpl_prelude = ' //! Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' //! for {lang} \n ' + \
' //! from codepoints {font_data} \n ' + \
' //! for use with font {ttf_files} \n \n '
2024-03-23 18:41:26 -07:00
ttf_files = [ ]
for ttf in cls . intermediate . get ( ' ttfs ' ) :
ttf_files . append ( ttf [ 2 ] )
result = tmpl_prelude . format ( lang = cls . language_name ,
font_data = cls . intermediate . get ( ' font_data ' ) ,
ttf_files = ' , ' . join ( ttf_files ) ,
font_name = cls . intermediate . get ( ' font_name ' ) . replace ( ' ' , ' ' ) )
tmpl_prelude_define_file_name = " pub const FONT_ICON_FILE_NAME_ {font_abbr} : &str = \" {file_name_ttf} \" ; \n "
for ttf in cls . intermediate . get ( ' ttfs ' ) :
result + = tmpl_prelude_define_file_name . format ( font_abbr = ttf [ 0 ] , file_name_ttf = ttf [ 1 ] )
result + = ' \n '
# min/max
tmpl_line_minmax = " pub const ICON_ {minmax} : char = ' \\ u {{ {val} }} ' ; \n "
result + = tmpl_line_minmax . format ( minmax = ' MIN ' ,
val = cls . intermediate . get ( ' font_min ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX_16 ' ,
val = cls . intermediate . get ( ' font_max_16 ' ) ) + \
tmpl_line_minmax . format ( minmax = ' MAX ' ,
2024-09-28 10:31:06 -07:00
val = cls . intermediate . get ( ' font_max ' ) ) + ' \n '
2024-03-23 18:41:26 -07:00
return result
@classmethod
def line_icon ( cls , icon ) :
tmpl_line_icon = " pub const ICON_ {icon} : char = ' \\ u {{ {code} }} ' ; \n "
icon_name = str . upper ( icon [ 0 ] ) . replace ( ' - ' , ' _ ' )
icon_code = icon [ 1 ]
result = tmpl_line_icon . format ( icon = icon_name , code = icon_code )
return result
class LanguageGo ( Language ) :
language_name = ' Go '
file_name = ' Icons {name} .go '
@classmethod
def prelude ( cls ) :
2024-09-28 10:31:06 -07:00
tmpl_prelude = ' // Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py \n ' + \
' // for {lang} \n ' + \
' // from codepoints {font_data} \n ' + \
' // for use with font {ttf_files} \n \n ' + \
2024-03-23 18:41:26 -07:00
' package IconFontCppHeaders \n \n '
ttf_files = [ ]
for ttf in cls . intermediate . get ( ' ttfs ' ) :
ttf_files . append ( ttf [ 2 ] )
result = tmpl_prelude . format ( lang = cls . language_name ,
font_data = cls . intermediate . get ( ' font_data ' ) ,
ttf_files = ' , ' . join ( ttf_files ) ,
package_name = str ( cls . intermediate . get ( ' font_name ' ) ) . replace ( ' ' , ' ' ) )
result + = ' var Icons {name} = Font ' . format ( name = str ( cls . intermediate . get ( ' font_name ' ) ) . replace ( ' ' , ' ' ) )
result + = ' { \n '
result + = ' \t Filenames: [][2]string { \n '
for ttf in cls . intermediate . get ( ' ttfs ' ) :
entry = ' " {font_abbr} " , " {file_name_ttf} " '
result + = ' \t \t { ' + entry . format ( font_abbr = ttf [ 0 ] , file_name_ttf = ttf [ 1 ] ) + ' }, \n '
result + = ' \t }, \n '
# min/max
tmpl_line_minmax = ' \t {minmax} : 0x {val} , \n '
abbreviation = cls . intermediate . get ( ' font_minmax_abbr ' ) if cls . intermediate . get ( ' font_minmax_abbr ' ) else cls . intermediate . get ( ' font_abbr ' )
result + = tmpl_line_minmax . format ( minmax = ' Min ' ,
abbr = abbreviation ,
val = cls . intermediate . get ( ' font_min ' ) ) + \
tmpl_line_minmax . format ( minmax = ' Max16 ' ,
abbr = abbreviation ,
val = cls . intermediate . get ( ' font_max_16 ' ) ) + \
tmpl_line_minmax . format ( minmax = ' Max ' ,
abbr = abbreviation ,
val = cls . intermediate . get ( ' font_max ' ) )
result + = ' \t Icons: map[string]string { \n '
return result
@classmethod
def line_icon ( cls , icon ) :
icon_name = cls . to_camelcase ( icon [ 0 ] )
tmpl_line_icon = ' \t \t " {icon} " : \t " {code} " , \t // U+ {unicode} \n '
icon_code = repr ( chr ( int ( icon [ 1 ] , 16 ) ) . encode ( ' utf-8 ' ) ) [ 2 : - 1 ]
result = tmpl_line_icon . format ( abbr = cls . intermediate . get ( ' font_abbr ' ) ,
icon = icon_name ,
code = icon_code ,
unicode = icon [ 1 ] )
return result
@classmethod
def epilogue ( cls ) :
return ' \t }, \n } \n '
@classmethod
def to_camelcase ( cls , text ) :
parts = text . split ( ' - ' )
for i in range ( len ( parts ) ) :
p = parts [ i ]
parts [ i ] = p [ 0 ] . upper ( ) + p [ 1 : ] . lower ( )
return ' ' . join ( parts )
# Main
2024-09-28 10:31:06 -07:00
fonts = [ FontFA4 , FontFA5 , FontFA5Brands , FontFA5Pro , FontFA5ProBrands , FontFA6 , FontFA6Brands , FontFK , FontMD , FontMS , FontMDI , FontKI , FontFAD , FontCI , FontLC ]
2024-03-23 18:41:26 -07:00
languages = [ LanguageC , LanguageCSharp , LanguagePython , LanguageRust , LanguageGo ]
ttf2headerC = False # convert ttf files to C and C++ headers
2024-09-28 10:31:06 -07:00
logging . basicConfig ( format = ' %(levelname)s : %(message)s ' , level = logging . WARNING )
2024-03-23 18:41:26 -07:00
intermediates = [ ]
for font in fonts :
try :
font_intermediate = font . get_intermediate_representation ( )
if font_intermediate :
intermediates . append ( font_intermediate )
except Exception as e :
logging . error ( e )
if intermediates :
for interm in intermediates :
Language . intermediate = interm
for lang in languages :
if lang :
lang . save_to_file ( )
if ttf2headerC and lang == LanguageC :
try :
lang . convert_ttf_to_header ( )
except Exception as e :
logging . error ( e )