@@ -4,6 +4,7 @@ import sys
44import psMat
55import re
66import os .path
7+ import argparse
78
89try :
910 #Load the module
@@ -13,60 +14,225 @@ except ImportError:
1314 sys .stderr .write ("FontForge module could not be loaded. Try installing fontforge python bindings\n " )
1415 sys .exit (1 )
1516
17+
18+ # argparse stuff
19+
20+ parser = argparse .ArgumentParser (description = 'Patches a given font with programming and web development related glyphs (mainly for vim-webdevicons)' )
21+ parser .add_argument ('font' , help = 'The path to the font to be patched (e.g. Inconsolata.otf)' )
22+ parser .add_argument ('-s' , '--use-single-width-glyphs' , dest = 'single' , action = 'store_true' , help = 'Whether to generate the glyphs as single-width not double-width (default is double-width)' , default = False )
23+ parser .add_argument ('-q' , '--quiet' , '--shutup' , dest = 'quiet' , action = 'store_true' , help = 'Do not generate verbose output' , default = False )
24+ args = parser .parse_args ()
25+
1626print "using fontforge package version: " + str (fontforge .__version__ )
1727
18- sourceFont = fontforge .open (sys .argv [1 ])
28+ additionalFontNameSuffix = " Plus Nerd File Types"
29+
30+ if args .single :
31+ additionalFontNameSuffix += " Mono"
32+
33+ sourceFont = fontforge .open (args .font )
1934
2035# rename font
2136fontname , style = re .match ("^([^-]*)(?:(-.*))?$" , sourceFont .fontname ).groups ()
22- sourceFont .familyname = sourceFont .familyname + " Plus Nerd File Types"
23- sourceFont .fullname = sourceFont .fullname + " Plus Nerd File Types"
24- sourceFont .fontname = fontname + 'PlusNerdFileTypes'
37+ sourceFont .familyname = sourceFont .familyname + additionalFontNameSuffix
38+ sourceFont .fullname = sourceFont .fullname + additionalFontNameSuffix
39+ sourceFont .fontname = fontname + additionalFontNameSuffix . replace ( " " , "" )
2540sourceFont .appendSFNTName ('English (US)' , 'Preferred Family' , sourceFont .familyname )
2641sourceFont .appendSFNTName ('English (US)' , 'Compatible Full' , sourceFont .fullname )
2742
2843# glyph font
2944
3045sourceFont_em_original = sourceFont .em
3146
32- # glyph fonts
33-
34- #Open a font
35- glyphFont1 = fontforge .open ("glyph-source-fonts/original-source.otf" )
36- ## @todo improve/fix
37- sourceFont .em = glyphFont1 .em
38- #select unicodes:
39- glyphFont1 .selection .select (("ranges" ,"unicode" ),0xE500 ,0xE51D )
40- #Copy those glyphs into the clipboard:
41- glyphFont1 .copy ()
42-
43- #select unicodes:
44- sourceFont .selection .select (("ranges" ,"unicode" ),0xE600 ,0xE61D )
45- #paste the glyphs above in:
46- sourceFont .paste ()
47-
48- # fix scaling of glyphs
49- sourceFont .em = sourceFont_em_original
50-
51- ### even more glyphs
52-
53- ##Open a font
54- glyphFont2 = fontforge .open ("glyph-source-fonts/devicons.ttf" )
55- ## @todo improve/fix
56- sourceFont .em = glyphFont2 .em
57- ##select unicodes:
58- glyphFont2 .selection .select (("ranges" ,"unicode" ),0xE600 ,0xE6A4 )
59- ##Copy those glyphs into the clipboard
60- glyphFont2 .copy ()
61- #
47+ symbols = fontforge .open ("glyph-source-fonts/original-source.otf" )
48+ symbols2 = fontforge .open ("glyph-source-fonts/devicons.ttf" )
49+
50+ symbolsRangeStart = 0xE500
51+ symbolsRangeEnd = 0xE521
52+
53+ symbols2RangeStart = 0xE600
54+ symbols2RangeEnd = 0xE6A4
55+
56+ sourceFontRange1Start = 0xE600
57+ sourceFontRange1End = 0xE621
58+
59+ sourceFontRange2Start = 0xE700
60+ sourceFontRange2End = 0xE7A4
61+
62+ SYM_ATTR = {
63+ # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly
64+ 0x2b60 : { 'align' : 'c' , 'stretch' : 'y' , 'overlap' : False },
65+ 0x2b61 : { 'align' : 'c' , 'stretch' : '' , 'overlap' : False },
66+ 0x2b62 : { 'align' : 'r' , 'stretch' : '' , 'overlap' : False },
67+ 0x2b63 : { 'align' : 'l' , 'stretch' : '' , 'overlap' : False },
68+ 0x2b64 : { 'align' : 'c' , 'stretch' : '' , 'overlap' : False },
69+ 0x2b80 : { 'align' : 'l' , 'stretch' : 'xy' , 'overlap' : True },
70+ 0x2b81 : { 'align' : 'l' , 'stretch' : 'xy' , 'overlap' : True },
71+ 0x2b82 : { 'align' : 'r' , 'stretch' : 'xy' , 'overlap' : True },
72+ 0x2b83 : { 'align' : 'r' , 'stretch' : 'xy' , 'overlap' : True },
73+ }
74+
75+
76+ # Force the em size to be equal
77+ symbols .em = sourceFont .em
78+ symbols2 .em = sourceFont .em
79+
80+ # Initial font dimensions
81+ font_dim = {
82+ 'xmin' : 0 ,
83+ 'ymin' : - sourceFont .descent ,
84+ 'xmax' : 0 ,
85+ 'ymax' : sourceFont .ascent ,
86+
87+ 'width' : 0 ,
88+ 'height' : 0 ,
89+ }
90+
91+ # Find the biggest char width and height
6292#
63- ## #select unicodes
64- sourceFont .selection .select (("ranges" ,"unicode" ),0xE700 ,0xE7A4 )
65- ##paste the glyphs above in:
66- sourceFont .paste ()
93+ # 0x00-0x17f is the Latin Extended-A range
94+ # 0x2500-0x2600 is the box drawing range
95+ for glyph in range (0x00 , 0x17f ) + range (0x2500 , 0x2600 ):
96+ try :
97+ (xmin , ymin , xmax , ymax ) = sourceFont [glyph ].boundingBox ()
98+ except TypeError :
99+ continue
100+
101+ if font_dim ['width' ] == 0 :
102+ font_dim ['width' ] = sourceFont [glyph ].width
103+
104+ if ymin < font_dim ['ymin' ]: font_dim ['ymin' ] = ymin
105+ if ymax > font_dim ['ymax' ]: font_dim ['ymax' ] = ymax
106+ if xmax > font_dim ['xmax' ]: font_dim ['xmax' ] = xmax
107+
108+ # Calculate font height
109+ font_dim ['height' ] = abs (font_dim ['ymin' ]) + font_dim ['ymax' ]
110+
111+ # Update the font encoding to ensure that the Unicode glyphs are available
112+ sourceFont .encoding = 'ISO10646'
113+
114+ # Fetch this property before adding outlines
115+ onlybitmaps = sourceFont .onlybitmaps
116+
117+ def get_dim (glyph ):
118+ bbox = glyph .boundingBox ()
119+
120+ return {
121+ 'xmin' : bbox [0 ],
122+ 'ymin' : bbox [1 ],
123+ 'xmax' : bbox [2 ],
124+ 'ymax' : bbox [3 ],
125+
126+ 'width' : bbox [2 ] + (- bbox [0 ]),
127+ 'height' : bbox [3 ] + (- bbox [1 ]),
128+ }
129+
130+ def copy_glyphs (sourceFont , sourceFontStart , sourceFontEnd , symbolFont , symbolFontStart , symbolFontEnd ):
131+
132+ sourceFontList = []
133+ sourceFontCounter = 0
134+
135+ for i in xrange (sourceFontStart , sourceFontEnd + 1 ):
136+ sourceFontList .append (format (i , 'X' ))
137+
138+ # Create glyphs from symbol font
139+
140+ symbolFont .selection .select (("ranges" ,"unicode" ),symbolFontStart ,symbolFontEnd )
141+ sourceFont .selection .select (("ranges" ,"unicode" ),sourceFontStart ,sourceFontEnd )
142+
143+ for sym_glyph in symbolFont .selection .byGlyphs :
144+ #sym_attr = SYM_ATTR[sym_glyph.unicode]
145+ if args .quiet == False :
146+ print "updating glyph: " + str (sym_glyph )
147+ # convince that this string really is a hex:
148+ currentSourceFontGlyph = int ("0x" + sourceFontList [sourceFontCounter ], 16 )
149+
150+ # Prepare symbol glyph dimensions
151+ sym_dim = get_dim (sym_glyph )
152+
153+ # Select and copy symbol from its encoding point
154+ symbolFont .selection .select (sym_glyph .encoding )
155+ symbolFont .copy ()
156+
157+ # Select and paste symbol to its unicode code point
158+ sourceFont .selection .select (currentSourceFontGlyph )
159+ sourceFont .paste ()
160+
161+ if args .single :
162+ # Now that we have copy/pasted the glyph, it's time to scale and move it
163+
164+ # Handle glyph stretching
165+ #if 'x' in sym_attr['stretch']:
166+ # # Stretch the glyph horizontally
167+ # scale_ratio = font_dim['width'] / sym_dim['width']
168+
169+ # sourceFont.transform(psMat.scale(scale_ratio, 1))
170+ #if 'y' in sym_attr['stretch']:
171+ # # Stretch the glyph vertically
172+ # scale_ratio = font_dim['height'] / sym_dim['height']
173+
174+ # sourceFont.transform(psMat.scale(1, scale_ratio))
175+
176+ # Use the dimensions from the pasted and stretched glyph
177+ sym_dim = get_dim (sourceFont [currentSourceFontGlyph ])
178+
179+ # Center-align the glyph vertically
180+ font_ycenter = font_dim ['height' ] / 2
181+ sym_ycenter = sym_dim ['height' ] / 2
182+
183+ # First move it to the ymax (top)
184+ sourceFont .transform (psMat .translate (0 , font_dim ['ymax' ] - sym_dim ['ymax' ]))
185+
186+ # Then move it the y center difference
187+ sourceFont .transform (psMat .translate (0 , sym_ycenter - font_ycenter ))
188+
189+ # Ensure that the glyph doesn't extend outside the font's bounding box
190+ if sym_dim ['width' ] > font_dim ['width' ]:
191+ # The glyph is too wide, scale it down to fit
192+ scale_matrix = psMat .scale (font_dim ['width' ] / sym_dim ['width' ], 1 )
193+
194+ sourceFont .transform (scale_matrix )
195+
196+ # Use the dimensions from the stretched glyph
197+ sym_dim = get_dim (sourceFont [currentSourceFontGlyph ])
198+
199+ # Handle glyph alignment
200+ #if sym_attr['align'] == 'c':
201+ # # Center align
202+ # align_matrix = psMat.translate(font_dim['width'] / 2 - sym_dim['width'] / 2 , 0)
203+ align_matrix = psMat .translate (font_dim ['width' ] / 2 - sym_dim ['width' ] / 2 , 0 )
204+ #elif sym_attr['align'] == 'r':
205+ # # Right align
206+ # align_matrix = psMat.translate(font_dim['width'] - sym_dim['width'], 0)
207+ #else:
208+ # No alignment (left alignment)
209+ #align_matrix = psMat.translate(0, 0)
210+
211+ sourceFont .transform (align_matrix )
212+
213+ #if sym_attr['overlap'] is True:
214+ # overlap_width = sourceFont.em / 48
215+
216+ # # Stretch the glyph slightly horizontally if it should overlap
217+ # sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1))
218+
219+ # if sym_attr['align'] == 'l':
220+ # # The glyph should be left-aligned, so it must be moved overlap_width to the left
221+ # # This only applies to left-aligned glyphs because the glyph is scaled to the right
222+ # sourceFont.transform(psMat.translate(-overlap_width, 0))
223+
224+ # Ensure the font is considered monospaced on Windows
225+ sourceFont [currentSourceFontGlyph ].width = font_dim ['width' ]
226+
227+ sourceFontCounter += 1
228+ # reset selection so iteration works propertly @todo fix? rookie misunderstanding?
229+ symbolFont .selection .select (("ranges" ,"unicode" ),symbolFontStart ,symbolFontEnd )
230+ # end for
231+ return
232+
67233
68- # fix scaling of glyphs
69- sourceFont . em = sourceFont_em_original
234+ copy_glyphs ( sourceFont , sourceFontRange1Start , sourceFontRange1End , symbols , symbolsRangeStart , symbolsRangeEnd )
235+ copy_glyphs ( sourceFont , sourceFontRange2Start , sourceFontRange2End , symbols2 , symbols2RangeStart , symbols2RangeEnd )
70236
71237extension = os .path .splitext (sourceFont .path )[1 ]
72238
@@ -77,5 +243,4 @@ sourceFont.generate(sourceFont.fullname + extension)
77243
78244print "Generated"
79245print sourceFont .fullname
80- print sourceFont .fontname
81246
0 commit comments