From fec7b20a4a37e43e02de2b917826962278757150 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Wed, 12 Oct 2016 20:12:08 -0700 Subject: [PATCH 01/15] Various improvements for mono-space generation --- font-patcher | 182 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 55 deletions(-) diff --git a/font-patcher b/font-patcher index 6ed9ce9da..18e8f390a 100755 --- a/font-patcher +++ b/font-patcher @@ -43,10 +43,10 @@ parser.add_argument('--pomicons', dest='pomicons', action='store_true', help='Ad parser.add_argument('--powerline', dest='powerline', action='store_true', help='Add Powerline Glyphs', default=False) parser.add_argument('--powerlineextra', dest='powerlineextra', action='store_true', help='Add Powerline Glyphs (https://github.com/ryanoasis/powerline-extra-symbols)', default=False) parser.add_argument('--careful', dest='careful', action='store_true', help='Do not overwrite existing glyphs if detected', default=False) +parser.add_argument('-ext', '--extension', type=str, nargs='?', dest='extension', help='Change type of font file to create (e.g. ttf, otf)', default="") parser.add_argument('-out', '--outputdir', type=str, nargs='?', dest='outputdir', help='The directory to output the patched font file to', default=".") args = parser.parse_args() - changelog = open("changelog.md", "r") minimumVersion = 20141231 actualVersion = int(fontforge.version()) @@ -180,6 +180,7 @@ sourceFont.version += ";" + projectName + " " + version # glyph font sourceFont_em_original = sourceFont.em +print("SourceFont.em: ", sourceFont.em) # Open fonts and force the em size to be equal @@ -190,7 +191,8 @@ symbolsDevicons = fontforge.open("glyph-source-fonts/devicons.ttf") symbols.em = sourceFont.em symbolsDevicons.em = sourceFont.em -# powerlineExtraSymbols.em = sourceFont.em +powerlineSymbols.em = sourceFont.em +powerlineExtraSymbols.em = sourceFont.em if args.fontawesome: fontawesome = fontforge.open("glyph-source-fonts/FontAwesome.otf") @@ -285,15 +287,77 @@ SYM_ATTR = { 0x2b81: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, 0x2b82: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, 0x2b83: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + + # Powerline dividers + + # Arrow tips + 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Rounded arcs + 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Bottom Triangles + 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Top Triangles + 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Flames + 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Small squares + 0xe0c4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c5: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Bigger squares + 0xe0c6: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + + # Waveform + 0xe0c8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + + # Hexagons + 0xe0cc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0cd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + + # Legos + 0xe0ce: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0cf: { 'align': 'c', 'stretch': 'xy', 'overlap': False }, + 0xe0d1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + + # Top and bottom trapezoid + 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, } +SYM_ATTR_DEFAULT = { + # 'pa' == preserve aspect ratio + 'align': 'c', 'stretch': 'pa', 'overlap': False + } + # Initial font dimensions font_dim = { + # Use winXXXXXX for ymin and ymax as this is typically what is used for line size 'xmin' : 0, - 'ymin' : -sourceFont.descent, + 'ymin' : -sourceFont.os2_windescent, 'xmax' : 0, - 'ymax' : sourceFont.ascent, + 'ymax' : sourceFont.os2_winascent, 'width' : 0, 'height': 0, } @@ -311,8 +375,12 @@ for glyph in range(0x00, 0x17f) + range(0x2500, 0x2600): if font_dim['width'] == 0: font_dim['width'] = sourceFont[glyph].width - if ymin < font_dim['ymin']: font_dim['ymin'] = ymin - if ymax > font_dim['ymax']: font_dim['ymax'] = ymax + if font_dim['width'] < sourceFont[glyph].width: + font_dim['width'] = sourceFont[glyph].width + + # Ignore the y-values, os2_winXXXXX values set above are more accurate + # if ymin < font_dim['ymin']: font_dim['ymin'] = ymin + # if ymax > font_dim['ymax']: font_dim['ymax'] = ymax if xmax > font_dim['xmax']: font_dim['xmax'] = xmax # Calculate font height @@ -354,7 +422,11 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo for sym_glyph in symbolFont.selection.byGlyphs: - #sym_attr = SYM_ATTR[sym_glyph.unicode] + try: + sym_attr = SYM_ATTR[sym_glyph.unicode] + except KeyError: + sym_attr = SYM_ATTR_DEFAULT + glyphName = sym_glyph.glyphname if exactEncoding: @@ -396,68 +468,65 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo sourceFont[currentSourceFontGlyph].glyphname = glyphName - if args.single: + # There are some symbols that are blank, skip those + if args.single and sym_dim['width'] and sym_dim['height']: # Now that we have copy/pasted the glyph, it's time to scale and move it # Handle glyph stretching - #if 'x' in sym_attr['stretch']: - # # Stretch the glyph horizontally - # scale_ratio = font_dim['width'] / sym_dim['width'] + scale_ratio_x = 1 + scale_ratio_y = 1 + if sym_attr['stretch'] == 'pa': + # We want to preserve x/y aspect ratio, so find biggest scale factor that allows + scale_ratio_x = font_dim['width'] / sym_dim['width'] + scale_ratio_y = font_dim['height'] / sym_dim['height'] + if scale_ratio_x > scale_ratio_y: + scale_ratio_x = scale_ratio_y + else: + scale_ratio_y = scale_ratio_x + else: + if 'x' in sym_attr['stretch']: + # Stretch the glyph horizontally + scale_ratio_x = font_dim['width'] / sym_dim['width'] + if 'y' in sym_attr['stretch']: + # Stretch the glyph vertically + scale_ratio_y = font_dim['height'] / sym_dim['height'] - # sourceFont.transform(psMat.scale(scale_ratio, 1)) - #if 'y' in sym_attr['stretch']: - # # Stretch the glyph vertically - # scale_ratio = font_dim['height'] / sym_dim['height'] - - # sourceFont.transform(psMat.scale(1, scale_ratio)) + sourceFont.transform(psMat.scale(scale_ratio_x, scale_ratio_y)) # Use the dimensions from the pasted and stretched glyph sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) - # Center-align the glyph vertically - font_ycenter = font_dim['height'] / 2 - sym_ycenter = sym_dim['height'] / 2 + # Center the symbol by matching the center of the font and center of symbol + sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) + font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) + sourceFont.transform(psMat.translate(0, font_ycenter - sym_ycenter)) - # First move it to the ymax (top) - sourceFont.transform(psMat.translate(0, font_dim['ymax'] - sym_dim['ymax'])) + # Handle glyph l/r alignment - # Then move it the y center difference - sourceFont.transform(psMat.translate(0, sym_ycenter - font_ycenter)) - - # Ensure that the glyph doesn't extend outside the font's bounding box - if sym_dim['width'] > font_dim['width']: - # The glyph is too wide, scale it down to fit - scale_matrix = psMat.scale(font_dim['width'] / sym_dim['width'], 1) - - sourceFont.transform(scale_matrix) - - # Use the dimensions from the stretched glyph - sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) - - # Handle glyph alignment - #if sym_attr['align'] == 'c': - # # Center align - # align_matrix = psMat.translate(font_dim['width'] / 2 - sym_dim['width'] / 2 , 0) - align_matrix = psMat.translate(font_dim['width'] / 2 - sym_dim['width'] / 2 , 0) - #elif sym_attr['align'] == 'r': - # # Right align - # align_matrix = psMat.translate(font_dim['width'] - sym_dim['width'], 0) - #else: - # No alignment (left alignment) - #align_matrix = psMat.translate(0, 0) + # First move it to the xmin (left) + left_align_distance = font_dim['xmin']-sym_dim['xmin'] + if sym_attr['align'] == 'c': + # Center align + align_matrix = psMat.translate(left_align_distance + ((font_dim['width']/2) - (sym_dim['width']/2)), 0) + elif sym_attr['align'] == 'r': + # Right align + align_matrix = psMat.translate(left_align_distance + font_dim['width'] - sym_dim['width'], 0) + else: + # Left align + align_matrix = psMat.translate(left_align_distance, 0) sourceFont.transform(align_matrix) - #if sym_attr['overlap'] is True: - # overlap_width = sourceFont.em / 48 + if sym_attr['overlap'] is True: + overlap_width = sourceFont.em / 48 - # # Stretch the glyph slightly horizontally if it should overlap - # sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1)) + # Stretch the glyph slightly horizontally if it should overlap + sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1)) - # if sym_attr['align'] == 'l': - # # The glyph should be left-aligned, so it must be moved overlap_width to the left - # # This only applies to left-aligned glyphs because the glyph is scaled to the right - # sourceFont.transform(psMat.translate(-overlap_width, 0)) + if sym_attr['align'] == 'l': + # The glyph should be left-aligned, so it must be moved overlap_width to the left + # This only applies to left-aligned glyphs because the glyph is scaled to the right + sourceFont.transform(psMat.translate(-overlap_width, 0)) # Ensure the font is considered monospaced on Windows sourceFont[currentSourceFontGlyph].width = font_dim['width'] @@ -495,7 +564,10 @@ if args.pomicons: if args.fontlinux: copy_glyphs(sourceFont, sourceFontFontLinuxStart, sourceFontFontLinuxEnd, fontlinux, symbolsFontLinuxRangeStart, symbolsFontLinuxRangeEnd, fontlinuxExactEncodingPosition) -extension = os.path.splitext(sourceFont.path)[1] +if args.extension == "": + extension = os.path.splitext(sourceFont.path)[1] +else: + extension = '.'+args.extension # the `PfEd-comments` flag is required for Fontforge to save # '.comment' and '.fontlog'. From ec419a80ba0d219b00b5c44b8303526a8c2ed12e Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Thu, 13 Oct 2016 17:48:30 -0700 Subject: [PATCH 02/15] Unified indents, auto-convert to otf when generating windows fonts. --- font-patcher | 383 ++++++++++++++++++++++++++------------------------- 1 file changed, 193 insertions(+), 190 deletions(-) diff --git a/font-patcher b/font-patcher index 18e8f390a..81fb43863 100755 --- a/font-patcher +++ b/font-patcher @@ -36,6 +36,7 @@ parser.add_argument('font', help='The path to the font to be patched (e.g. Incon 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) parser.add_argument('-q', '--quiet', '--shutup', dest='quiet', action='store_true', help='Do not generate verbose output', default=False) parser.add_argument('-w', '--windows', '--limit-font-name-length', dest='windows', action='store_true', help='Limit the internal font name to a maximum of 31 characters (for safe Windows compatiblity)', default=False) +parser.add_argument('-c', '--complete', dest='complete', action='store_true', help='Add all availale Glyphs', default=False) parser.add_argument('--fontawesome', dest='fontawesome', action='store_true', help='Add Font Awesome Glyphs (http://fortawesome.github.io/Font-Awesome)', default=False) parser.add_argument('--fontlinux', dest='fontlinux', action='store_true', help='Add Font Linux Glyphs (https://github.com/Lukas-W/font-linux)', default=False) parser.add_argument('--octicons', dest='octicons', action='store_true', help='Add Octicons Glyphs (https://octicons.github.com)', default=False) @@ -59,9 +60,16 @@ if actualVersion < minimumVersion: print projectName + ": Please use at least version: " + str(minimumVersion) sys.exit(1) - verboseAdditionalFontNameSuffix = " " + projectNameSingular +if args.complete: + args.fontawesome = True + args.fontlinux = True + args.octicons = True + args.pomicons = True + args.powerline = True + args.powerlineextra = True + if args.windows: # attempt to shorten here on the additional name BEFORE trimming later additionalFontNameSuffix = " " + projectNameAbbreviation @@ -93,6 +101,9 @@ if args.fontawesome and args.octicons and args.pomicons and args.powerlineextra if args.single: additionalFontNameSuffix += " Mono" verboseAdditionalFontNameSuffix += " Mono" + # Windows doesn't properly detect patched ttf font files as monotype, but works properly with otf, so force the issue + if args.windows and args.extension=="": + args.extension = "otf" sourceFont = fontforge.open(args.font) @@ -154,7 +165,7 @@ def make_sure_path_exists(path): os.makedirs(path) except OSError as exception: if exception.errno != errno.EEXIST: - raisee + raise make_sure_path_exists(args.outputdir) @@ -177,11 +188,6 @@ sourceFont.fontlog = projectInfo + "\n\n" + changelog.read() sourceFont.version += ";" + projectName + " " + version #print "Version now is " + sourceFont.version -# glyph font - -sourceFont_em_original = sourceFont.em -print("SourceFont.em: ", sourceFont.em) - # Open fonts and force the em size to be equal symbols = fontforge.open("glyph-source-fonts/original-source.otf") @@ -277,89 +283,88 @@ sourceFontFontLinuxEnd = 0xF315 SYM_ATTR = { - # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly - 0x2b60: { 'align': 'c', 'stretch': 'y' , 'overlap': False }, - 0x2b61: { 'align': 'c', 'stretch': '' , 'overlap': False }, - 0x2b62: { 'align': 'r', 'stretch': '' , 'overlap': False }, - 0x2b63: { 'align': 'l', 'stretch': '' , 'overlap': False }, - 0x2b64: { 'align': 'c', 'stretch': '' , 'overlap': False }, - 0x2b80: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0x2b81: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0x2b82: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0x2b83: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly + 0x2b60: { 'align': 'c', 'stretch': 'y' , 'overlap': False }, + 0x2b61: { 'align': 'c', 'stretch': '' , 'overlap': False }, + 0x2b62: { 'align': 'r', 'stretch': '' , 'overlap': False }, + 0x2b63: { 'align': 'l', 'stretch': '' , 'overlap': False }, + 0x2b64: { 'align': 'c', 'stretch': '' , 'overlap': False }, + 0x2b80: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0x2b81: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0x2b82: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0x2b83: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - # Powerline dividers + # Powerline dividers - # Arrow tips - 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Arrow tips + 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Rounded arcs - 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Rounded arcs + 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Bottom Triangles - 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Bottom Triangles + 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Top Triangles - 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Top Triangles + 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Flames - 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Flames + 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Small squares - 0xe0c4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c5: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Small squares + 0xe0c4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c5: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Bigger squares - 0xe0c6: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Bigger squares + 0xe0c6: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - # Waveform - 0xe0c8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + # Waveform + 0xe0c8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - # Hexagons - 0xe0cc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0cd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + # Hexagons + 0xe0cc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0cd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - # Legos - 0xe0ce: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0cf: { 'align': 'c', 'stretch': 'xy', 'overlap': False }, - 0xe0d1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + # Legos + 0xe0ce: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0cf: { 'align': 'c', 'stretch': 'xy', 'overlap': False }, + 0xe0d1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - # Top and bottom trapezoid - 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + # Top and bottom trapezoid + 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, } SYM_ATTR_DEFAULT = { - # 'pa' == preserve aspect ratio - 'align': 'c', 'stretch': 'pa', 'overlap': False - } - + # 'pa' == preserve aspect ratio + 'align': 'c', 'stretch': 'pa', 'overlap': False +} # Initial font dimensions font_dim = { - # Use winXXXXXX for ymin and ymax as this is typically what is used for line size - 'xmin' : 0, - 'ymin' : -sourceFont.os2_windescent, - 'xmax' : 0, - 'ymax' : sourceFont.os2_winascent, - 'width' : 0, - 'height': 0, + # Use winXXXXXX for ymin and ymax as this is typically what is used for line size + 'xmin' : 0, + 'ymin' : -sourceFont.os2_windescent, + 'xmax' : 0, + 'ymax' : sourceFont.os2_winascent, + 'width' : 0, + 'height': 0, } # Find the biggest char width and height @@ -367,21 +372,21 @@ font_dim = { # 0x00-0x17f is the Latin Extended-A range # 0x2500-0x2600 is the box drawing range for glyph in range(0x00, 0x17f) + range(0x2500, 0x2600): - try: - (xmin, ymin, xmax, ymax) = sourceFont[glyph].boundingBox() - except TypeError: - continue + try: + (xmin, ymin, xmax, ymax) = sourceFont[glyph].boundingBox() + except TypeError: + continue - if font_dim['width'] == 0: - font_dim['width'] = sourceFont[glyph].width + if font_dim['width'] == 0: + font_dim['width'] = sourceFont[glyph].width - if font_dim['width'] < sourceFont[glyph].width: - font_dim['width'] = sourceFont[glyph].width + if font_dim['width'] < sourceFont[glyph].width: + font_dim['width'] = sourceFont[glyph].width - # Ignore the y-values, os2_winXXXXX values set above are more accurate - # if ymin < font_dim['ymin']: font_dim['ymin'] = ymin - # if ymax > font_dim['ymax']: font_dim['ymax'] = ymax - if xmax > font_dim['xmax']: font_dim['xmax'] = xmax + # Ignore the y-values, os2_winXXXXX values set above are more accurate + # if ymin < font_dim['ymin']: font_dim['ymin'] = ymin + # if ymax > font_dim['ymax']: font_dim['ymax'] = ymax + if xmax > font_dim['xmax']: font_dim['xmax'] = xmax # Calculate font height font_dim['height'] = abs(font_dim['ymin']) + font_dim['ymax'] @@ -393,18 +398,17 @@ sourceFont.encoding = 'ISO10646' onlybitmaps = sourceFont.onlybitmaps def get_dim(glyph): - bbox = glyph.boundingBox() + bbox = glyph.boundingBox() - return { - 'xmin' : bbox[0], - 'ymin' : bbox[1], - 'xmax' : bbox[2], - 'ymax' : bbox[3], - - 'width' : bbox[2] + (-bbox[0]), - 'height': bbox[3] + (-bbox[1]), - } + return { + 'xmin' : bbox[0], + 'ymin' : bbox[1], + 'xmax' : bbox[2], + 'ymax' : bbox[3], + 'width' : bbox[2] + (-bbox[0]), + 'height': bbox[3] + (-bbox[1]), + } def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False): @@ -421,125 +425,125 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo sourceFont.selection.select(("ranges","unicode"),sourceFontStart,sourceFontEnd) for sym_glyph in symbolFont.selection.byGlyphs: + try: + sym_attr = SYM_ATTR[sym_glyph.unicode] + except KeyError: + sym_attr = SYM_ATTR_DEFAULT + glyphName = sym_glyph.glyphname + + if exactEncoding: + # use the exact same hex values for the source font as for the symbol font + currentSourceFontGlyph = sym_glyph.encoding + copiedToSlot = str(sym_glyph.unicode) + else: + # use source font defined hex values based on passed in start and end + # convince that this string really is a hex: + currentSourceFontGlyph = int("0x" + sourceFontList[sourceFontCounter], 16) + copiedToSlot = sourceFontList[sourceFontCounter] + + if args.quiet == False: + print "updating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + str(copiedToSlot) + + # Prepare symbol glyph dimensions + sym_dim = get_dim(sym_glyph) + + # Select and copy symbol from its encoding point + symbolFont.selection.select(sym_glyph.encoding) + symbolFont.copy() + + # check it + if args.careful: + + if copiedToSlot.startswith("uni"): + copiedToSlot = copiedToSlot[3:] + + codepoint = int("0x" + copiedToSlot, 16) try: - sym_attr = SYM_ATTR[sym_glyph.unicode] - except KeyError: - sym_attr = SYM_ATTR_DEFAULT - - glyphName = sym_glyph.glyphname - - if exactEncoding: - # use the exact same hex values for the source font as for the symbol font - currentSourceFontGlyph = sym_glyph.encoding - copiedToSlot = str(sym_glyph.unicode) - else: - # use source font defined hex values based on passed in start and end - # convince that this string really is a hex: - currentSourceFontGlyph = int("0x" + sourceFontList[sourceFontCounter], 16) - copiedToSlot = sourceFontList[sourceFontCounter] - - if args.quiet == False: - print "updating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + str(copiedToSlot) - - # Prepare symbol glyph dimensions - sym_dim = get_dim(sym_glyph) - - # Select and copy symbol from its encoding point - symbolFont.selection.select(sym_glyph.encoding) - symbolFont.copy() - - # check it - if args.careful: - - if copiedToSlot.startswith("uni"): - copiedToSlot = copiedToSlot[3:] - - codepoint = int("0x" + copiedToSlot, 16) - try: - sourceFont[codepoint] - except TypeError: - # nothing there go ahead and paste at this codepoint - sourceFont.selection.select(currentSourceFontGlyph) - sourceFont.paste() - else: + sourceFont[codepoint] + except TypeError: + # nothing there go ahead and paste at this codepoint sourceFont.selection.select(currentSourceFontGlyph) sourceFont.paste() + else: + sourceFont.selection.select(currentSourceFontGlyph) + sourceFont.paste() - sourceFont[currentSourceFontGlyph].glyphname = glyphName + sourceFont[currentSourceFontGlyph].glyphname = glyphName - # There are some symbols that are blank, skip those - if args.single and sym_dim['width'] and sym_dim['height']: - # Now that we have copy/pasted the glyph, it's time to scale and move it + # There are some symbols that are blank, skip those + if args.single and sym_dim['width'] and sym_dim['height']: + # Now that we have copy/pasted the glyph, it's time to scale and move it - # Handle glyph stretching - scale_ratio_x = 1 - scale_ratio_y = 1 - if sym_attr['stretch'] == 'pa': - # We want to preserve x/y aspect ratio, so find biggest scale factor that allows - scale_ratio_x = font_dim['width'] / sym_dim['width'] - scale_ratio_y = font_dim['height'] / sym_dim['height'] - if scale_ratio_x > scale_ratio_y: - scale_ratio_x = scale_ratio_y - else: - scale_ratio_y = scale_ratio_x + # Handle glyph stretching + scale_ratio_x = 1 + scale_ratio_y = 1 + if sym_attr['stretch'] == 'pa': + # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit + scale_ratio_x = font_dim['width'] / sym_dim['width'] + # font_dim['height'] represents total line height, keep our symbols sized based upon font's em + scale_ratio_y = sourceFont.em / sym_dim['height'] + if scale_ratio_x > scale_ratio_y: + scale_ratio_x = scale_ratio_y else: - if 'x' in sym_attr['stretch']: - # Stretch the glyph horizontally - scale_ratio_x = font_dim['width'] / sym_dim['width'] - if 'y' in sym_attr['stretch']: - # Stretch the glyph vertically - scale_ratio_y = font_dim['height'] / sym_dim['height'] + scale_ratio_y = scale_ratio_x + else: + if 'x' in sym_attr['stretch']: + # Stretch the glyph horizontally + scale_ratio_x = font_dim['width'] / sym_dim['width'] + if 'y' in sym_attr['stretch']: + # Stretch the glyph vertically to total line height (good for powerline separators) + scale_ratio_y = font_dim['height'] / sym_dim['height'] + if scale_ratio_x != 1 or scale_ratio_y != 1: sourceFont.transform(psMat.scale(scale_ratio_x, scale_ratio_y)) - # Use the dimensions from the pasted and stretched glyph - sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) + # Use the dimensions from the pasted and stretched glyph + sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) - # Center the symbol by matching the center of the font and center of symbol - sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) - font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) - sourceFont.transform(psMat.translate(0, font_ycenter - sym_ycenter)) + # Center the symbol by matching the center of the line height and center of symbol + sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) + font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) + sourceFont.transform(psMat.translate(0, font_ycenter - sym_ycenter)) - # Handle glyph l/r alignment + # Handle glyph l/r alignment - # First move it to the xmin (left) - left_align_distance = font_dim['xmin']-sym_dim['xmin'] - if sym_attr['align'] == 'c': - # Center align - align_matrix = psMat.translate(left_align_distance + ((font_dim['width']/2) - (sym_dim['width']/2)), 0) - elif sym_attr['align'] == 'r': - # Right align - align_matrix = psMat.translate(left_align_distance + font_dim['width'] - sym_dim['width'], 0) - else: - # Left align - align_matrix = psMat.translate(left_align_distance, 0) + # First move it to the xmin (left) + left_align_distance = font_dim['xmin']-sym_dim['xmin'] + if sym_attr['align'] == 'c': + # Center align + align_matrix = psMat.translate(left_align_distance + ((font_dim['width']/2) - (sym_dim['width']/2)), 0) + elif sym_attr['align'] == 'r': + # Right align + align_matrix = psMat.translate(left_align_distance + font_dim['width'] - sym_dim['width'], 0) + else: + # Left align + align_matrix = psMat.translate(left_align_distance, 0) - sourceFont.transform(align_matrix) + sourceFont.transform(align_matrix) - if sym_attr['overlap'] is True: - overlap_width = sourceFont.em / 48 + if sym_attr['overlap'] is True: + overlap_width = sourceFont.em / 48 - # Stretch the glyph slightly horizontally if it should overlap - sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1)) + # Stretch the glyph slightly horizontally if it should overlap + sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1)) - if sym_attr['align'] == 'l': - # The glyph should be left-aligned, so it must be moved overlap_width to the left - # This only applies to left-aligned glyphs because the glyph is scaled to the right - sourceFont.transform(psMat.translate(-overlap_width, 0)) + if sym_attr['align'] == 'l': + # The glyph should be left-aligned, so it must be moved overlap_width to the left + # This only applies to left-aligned glyphs because the glyph is scaled to the right + sourceFont.transform(psMat.translate(-overlap_width, 0)) - # Ensure the font is considered monospaced on Windows - sourceFont[currentSourceFontGlyph].width = font_dim['width'] + # Ensure the font is considered monospaced on Windows + sourceFont[currentSourceFontGlyph].width = font_dim['width'] - if exactEncoding is False: - sourceFontCounter += 1 + if exactEncoding is False: + sourceFontCounter += 1 - # reset selection so iteration works propertly @todo fix? rookie misunderstanding? - symbolFont.selection.select(("ranges","unicode"),symbolFontStart,symbolFontEnd) + # reset selection so iteration works propertly @todo fix? rookie misunderstanding? + symbolFont.selection.select(("ranges","unicode"),symbolFontStart,symbolFontEnd) # end for return - copy_glyphs(sourceFont, sourceFontOriginalStart, sourceFontOriginalEnd, symbols, symbolsOriginalRangeStart, symbolsOriginalRangeEnd) copy_glyphs(sourceFont, sourceFontDeviconsStart, sourceFontDeviconsEnd, symbolsDevicons, symbolsDeviconsRangeStart, symbolsDeviconsRangeEnd) @@ -575,4 +579,3 @@ sourceFont.generate(args.outputdir + "/" + sourceFont.fullname + extension, flag print "Generated" print sourceFont.fullname - From ab4f00e3ff69e2f3d0d0361fa8378ea95fbb4726 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Thu, 13 Oct 2016 23:00:59 -0700 Subject: [PATCH 03/15] Fixed windows ttf monospace misdetection and removed work around --- font-patcher | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/font-patcher b/font-patcher index 81fb43863..f9527f484 100755 --- a/font-patcher +++ b/font-patcher @@ -101,9 +101,6 @@ if args.fontawesome and args.octicons and args.pomicons and args.powerlineextra if args.single: additionalFontNameSuffix += " Mono" verboseAdditionalFontNameSuffix += " Mono" - # Windows doesn't properly detect patched ttf font files as monotype, but works properly with otf, so force the issue - if args.windows and args.extension=="": - args.extension = "otf" sourceFont = fontforge.open(args.font) @@ -533,6 +530,7 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # This only applies to left-aligned glyphs because the glyph is scaled to the right sourceFont.transform(psMat.translate(-overlap_width, 0)) + if args.single: # Ensure the font is considered monospaced on Windows sourceFont[currentSourceFontGlyph].width = font_dim['width'] From d8b760aeed029d95ae5a42cc4bb89d970e78e91b Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 14 Oct 2016 00:35:44 -0700 Subject: [PATCH 04/15] Work around for monospace ttf fonts not being detected by windows. --- font-patcher | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/font-patcher b/font-patcher index f9527f484..ee724a6ab 100755 --- a/font-patcher +++ b/font-patcher @@ -407,6 +407,11 @@ def get_dim(glyph): 'height': bbox[3] + (-bbox[1]), } +def set_width(sourceFont, width): + sourceFont.selection.all() + for glyph in sourceFont.selection.byGlyphs: + glyph.width = width + def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False): if exactEncoding is False: @@ -542,6 +547,17 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # end for return +if args.extension == "": + extension = os.path.splitext(sourceFont.path)[1] +else: + extension = '.'+args.extension + +if args.single and extension == '.ttf': + # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows. + # This needs to be done on all characters, as some information seems to be lost in the original font file. + # Seen only as a problem with ttf files, otf files seem to be okay. + set_width(sourceFont, font_dim['width']) + copy_glyphs(sourceFont, sourceFontOriginalStart, sourceFontOriginalEnd, symbols, symbolsOriginalRangeStart, symbolsOriginalRangeEnd) copy_glyphs(sourceFont, sourceFontDeviconsStart, sourceFontDeviconsEnd, symbolsDevicons, symbolsDeviconsRangeStart, symbolsDeviconsRangeEnd) @@ -566,11 +582,6 @@ if args.pomicons: if args.fontlinux: copy_glyphs(sourceFont, sourceFontFontLinuxStart, sourceFontFontLinuxEnd, fontlinux, symbolsFontLinuxRangeStart, symbolsFontLinuxRangeEnd, fontlinuxExactEncodingPosition) -if args.extension == "": - extension = os.path.splitext(sourceFont.path)[1] -else: - extension = '.'+args.extension - # the `PfEd-comments` flag is required for Fontforge to save # '.comment' and '.fontlog'. sourceFont.generate(args.outputdir + "/" + sourceFont.fullname + extension, flags=('opentype', 'PfEd-comments')) From 5583c6e342e0029d2d1470c33a5a71543012696d Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 14 Oct 2016 09:23:56 -0700 Subject: [PATCH 05/15] Do not truncate subfamily name to avoid MacOS treating fonts as the same --- font-patcher | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/font-patcher b/font-patcher index ee724a6ab..2ff95941e 100755 --- a/font-patcher +++ b/font-patcher @@ -133,10 +133,8 @@ except IndexError: if subFamily == "Regular": subFamily = fallbackStyle -fontname += " - " + subFamily - if args.windows: - maxLength = 31 + maxLength = 31 - len('-'+subFamily) familyname += " " + projectNameAbbreviation fullname += " Windows Compatible" # now make sure less than 32 characters name length @@ -149,6 +147,10 @@ if args.windows: else: familyname += " " + projectNameSingular +# Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with +# the same name as the same font, even if subFamily is different. +fontname += '-' + subFamily + # rename font def replace_all(text, dic): From bcfd8c1f5aa22cad568fc72ae61c3eb2445006af Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 14 Oct 2016 23:19:10 -0700 Subject: [PATCH 06/15] Use common scale factor for all glyphs from the same symbol font. --- font-patcher | 120 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/font-patcher b/font-patcher index 2ff95941e..bfa5c6fab 100755 --- a/font-patcher +++ b/font-patcher @@ -77,30 +77,30 @@ else: additionalFontNameSuffix = verboseAdditionalFontNameSuffix if args.fontawesome: - additionalFontNameSuffix += " Plus Font Awesome" + additionalFontNameSuffix += " A" verboseAdditionalFontNameSuffix += " Plus Font Awesome" if args.octicons: - additionalFontNameSuffix += " Plus Octicons" + additionalFontNameSuffix += " O" verboseAdditionalFontNameSuffix += " Plus Octicons" if args.pomicons: - additionalFontNameSuffix += " Plus Pomicons" + additionalFontNameSuffix += " P" verboseAdditionalFontNameSuffix += " Plus Pomicons" if args.fontlinux: - additionalFontNameSuffix += " Plus Font Linux" + additionalFontNameSuffix += " L" verboseAdditionalFontNameSuffix += " Plus Font Linux" # if all source glyphs included simplify the name if args.fontawesome and args.octicons and args.pomicons and args.powerlineextra and args.fontlinux: - additionalFontNameSuffix = " " + projectNameSingular + " Complete" + additionalFontNameSuffix = " " + projectNameSingular + " C" verboseAdditionalFontNameSuffix = " " + projectNameSingular + " Complete" # add mono signifier to end of name if args.single: - additionalFontNameSuffix += " Mono" - verboseAdditionalFontNameSuffix += " Mono" + additionalFontNameSuffix += " M" + verboseAdditionalFontNameSuffix += " M" sourceFont = fontforge.open(args.font) @@ -226,8 +226,8 @@ if args.fontawesome or args.octicons: fontlinuxExactEncodingPosition = False # Define the character ranges - # Symbol font ranges + symbolsPomiconsRangeStart = 0xE000 symbolsPomiconsRangeEnd = 0xE00A @@ -280,6 +280,15 @@ sourceFontOcticonsEnd = 0xF4DB sourceFontFontLinuxStart = 0xF300 sourceFontFontLinuxEnd = 0xF315 +# To keep the size of glyphs constant when scaling, choose a larger +# sized glyph from each symbol font to set the scaling amount +symbolsPomiconsScaleGlyph = 0xE000 # first symbol +symbolsPowerlineScaleGlyph = 0xE0A0 # scm branch symbol +symbolsPowerlineExtraScaleGlyph = 0xE70E # Android logo +symbolsDeviconsScaleGlyph = 0xE60E # Android logo +symbolsFontAwesomeScaleGlyph = 0xF17A # Windows logo +symbolsOcticonsScaleGlyph = 0xF02E # magnifying glass +symbolsFontLinuxScaleGlyph = 0xF10E # Ubuntu logo SYM_ATTR = { # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly @@ -357,7 +366,7 @@ SYM_ATTR_DEFAULT = { # Initial font dimensions font_dim = { - # Use winXXXXXX for ymin and ymax as this is typically what is used for line size + # Use os2_winXXXXXX for ymin and ymax as this is typically what is used for line size 'xmin' : 0, 'ymin' : -sourceFont.os2_windescent, 'xmax' : 0, @@ -414,7 +423,17 @@ def set_width(sourceFont, width): for glyph in sourceFont.selection.byGlyphs: glyph.width = width -def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False): +def get_scale_factor(font_dim, sym_dim): + # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit + scale_ratio_x = font_dim['width'] / sym_dim['width'] + # font_dim['height'] represents total line height, keep our symbols sized based upon font's em + scale_ratio_y = sourceFont.em / sym_dim['height'] + if scale_ratio_x > scale_ratio_y: + return scale_ratio_y + else: + return scale_ratio_x + +def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False, scaleGlyph=None): if exactEncoding is False: sourceFontList = [] @@ -423,8 +442,12 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo for i in xrange(sourceFontStart, sourceFontEnd + 1): sourceFontList.append(format(i, 'X')) - # Create glyphs from symbol font + scale_factor = 0 + if scaleGlyph: + sym_dim = get_dim(symbolFont[scaleGlyph]) + scale_factor = get_scale_factor(font_dim, sym_dim) + # Create glyphs from symbol font symbolFont.selection.select(("ranges","unicode"),symbolFontStart,symbolFontEnd) sourceFont.selection.select(("ranges","unicode"),sourceFontStart,sourceFontEnd) @@ -475,25 +498,28 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo sourceFont[currentSourceFontGlyph].glyphname = glyphName - # There are some symbols that are blank, skip those + # Now that we have copy/pasted the glyph, if we are creating a monospace + # font we need to scale and move the glyphs. It is possible to have + # empty glyphs, so we need to skip those. if args.single and sym_dim['width'] and sym_dim['height']: - # Now that we have copy/pasted the glyph, it's time to scale and move it - - # Handle glyph stretching scale_ratio_x = 1 scale_ratio_y = 1 + # If we want to preserve that aspect ratio of the glyphs we need to + # find the largest possible scaling factor that will allow the glyph + # to fit in both the x and y directions if sym_attr['stretch'] == 'pa': - # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit - scale_ratio_x = font_dim['width'] / sym_dim['width'] - # font_dim['height'] represents total line height, keep our symbols sized based upon font's em - scale_ratio_y = sourceFont.em / sym_dim['height'] - if scale_ratio_x > scale_ratio_y: - scale_ratio_x = scale_ratio_y + if scale_factor: + # We want to preserve the relative size of each glyph to other glyphs + # in the same symbol font. + scale_ratio_x = scale_factor + scale_ratio_y = scale_factor else: + # In this case, each glyph is sized independantly to each other + scale_ratio_x = get_scale_factor(font_dim, sym_dim) scale_ratio_y = scale_ratio_x else: if 'x' in sym_attr['stretch']: - # Stretch the glyph horizontally + # Stretch the glyph horizontally to fit the entire available width scale_ratio_x = font_dim['width'] / sym_dim['width'] if 'y' in sym_attr['stretch']: # Stretch the glyph vertically to total line height (good for powerline separators) @@ -502,28 +528,26 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo if scale_ratio_x != 1 or scale_ratio_y != 1: sourceFont.transform(psMat.scale(scale_ratio_x, scale_ratio_y)) - # Use the dimensions from the pasted and stretched glyph + # Use the dimensions from the newly pasted and stretched glyph sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) - # Center the symbol by matching the center of the line height and center of symbol + # Center the symbol vertically by matching the center of the line height and center of symbol sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) - sourceFont.transform(psMat.translate(0, font_ycenter - sym_ycenter)) + y_align_distance = font_ycenter - sym_ycenter - # Handle glyph l/r alignment + # Handle glyph l/r/c alignment - # First move it to the xmin (left) - left_align_distance = font_dim['xmin']-sym_dim['xmin'] + # First find the baseline x-alignment (left alignment amount) + x_align_distance = font_dim['xmin']-sym_dim['xmin'] if sym_attr['align'] == 'c': # Center align - align_matrix = psMat.translate(left_align_distance + ((font_dim['width']/2) - (sym_dim['width']/2)), 0) + x_align_distance += (font_dim['width']/2) - (sym_dim['width']/2) elif sym_attr['align'] == 'r': # Right align - align_matrix = psMat.translate(left_align_distance + font_dim['width'] - sym_dim['width'], 0) - else: - # Left align - align_matrix = psMat.translate(left_align_distance, 0) + x_align_distance += font_dim['width'] - sym_dim['width'] + align_matrix = psMat.translate(x_align_distance, y_align_distance) sourceFont.transform(align_matrix) if sym_attr['overlap'] is True: @@ -538,13 +562,17 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo sourceFont.transform(psMat.translate(-overlap_width, 0)) if args.single: - # Ensure the font is considered monospaced on Windows + # Ensure the font is considered monospaced on Windows by setting the same + # width for all character glyphs. + # This needs to be done for all glyphs, even the ones that are empty and + # didn't go through the scaling operations. sourceFont[currentSourceFontGlyph].width = font_dim['width'] if exactEncoding is False: sourceFontCounter += 1 # reset selection so iteration works propertly @todo fix? rookie misunderstanding? + # This is likely needed because the selection was changed when the glyph was copy/pasted symbolFont.selection.select(("ranges","unicode"),symbolFontStart,symbolFontEnd) # end for return @@ -556,33 +584,33 @@ else: if args.single and extension == '.ttf': # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows. - # This needs to be done on all characters, as some information seems to be lost in the original font file. - # Seen only as a problem with ttf files, otf files seem to be okay. + # This needs to be done on all characters, as some information seems to be lost from the original font file. + # This is only a problem with ttf files, otf files seem to be okay. set_width(sourceFont, font_dim['width']) copy_glyphs(sourceFont, sourceFontOriginalStart, sourceFontOriginalEnd, symbols, symbolsOriginalRangeStart, symbolsOriginalRangeEnd) -copy_glyphs(sourceFont, sourceFontDeviconsStart, sourceFontDeviconsEnd, symbolsDevicons, symbolsDeviconsRangeStart, symbolsDeviconsRangeEnd) +copy_glyphs(sourceFont, sourceFontDeviconsStart, sourceFontDeviconsEnd, symbolsDevicons, symbolsDeviconsRangeStart, symbolsDeviconsRangeEnd, scaleGlyph=symbolsDeviconsScaleGlyph) if args.powerline: - copy_glyphs(sourceFont, symbolsPowerlineRange1Start, symbolsPowerlineRange1End, powerlineSymbols, symbolsPowerlineRange1Start, symbolsPowerlineRange1End) - copy_glyphs(sourceFont, symbolsPowerlineRange2Start, symbolsPowerlineRange2End, powerlineSymbols, symbolsPowerlineRange2Start, symbolsPowerlineRange2End) + copy_glyphs(sourceFont, symbolsPowerlineRange1Start, symbolsPowerlineRange1End, powerlineSymbols, symbolsPowerlineRange1Start, symbolsPowerlineRange1End, scaleGlyph=symbolsPowerlineScaleGlyph) + copy_glyphs(sourceFont, symbolsPowerlineRange2Start, symbolsPowerlineRange2End, powerlineSymbols, symbolsPowerlineRange2Start, symbolsPowerlineRange2End, scaleGlyph=symbolsPowerlineScaleGlyph) if args.powerlineextra: - copy_glyphs(sourceFont, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, powerlineExtraSymbols, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, True) - copy_glyphs(sourceFont, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, powerlineExtraSymbols, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, True) - copy_glyphs(sourceFont, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, powerlineExtraSymbols, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, True) + copy_glyphs(sourceFont, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, powerlineExtraSymbols, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) + copy_glyphs(sourceFont, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, powerlineExtraSymbols, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) + copy_glyphs(sourceFont, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, powerlineExtraSymbols, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) if args.fontawesome: - copy_glyphs(sourceFont, sourceFontFontAwesomeStart, sourceFontFontAwesomeEnd, fontawesome, symbolsFontAwesomeRangeStart, symbolsFontAwesomeRangeEnd, True) + copy_glyphs(sourceFont, sourceFontFontAwesomeStart, sourceFontFontAwesomeEnd, fontawesome, symbolsFontAwesomeRangeStart, symbolsFontAwesomeRangeEnd, True, scaleGlyph=symbolsFontAwesomeScaleGlyph) if args.octicons: - copy_glyphs(sourceFont, sourceFontOcticonsStart, sourceFontOcticonsEnd, octicons, symbolsOcticonsRangeStart, symbolsOcticonsRangeEnd, octiconsExactEncodingPosition) + copy_glyphs(sourceFont, sourceFontOcticonsStart, sourceFontOcticonsEnd, octicons, symbolsOcticonsRangeStart, symbolsOcticonsRangeEnd, octiconsExactEncodingPosition, scaleGlyph=symbolsOcticonsScaleGlyph) if args.pomicons: - copy_glyphs(sourceFont, sourceFontPomiconsStart, sourceFontPomiconsEnd, pomicons, symbolsPomiconsRangeStart, symbolsPomiconsRangeEnd) + copy_glyphs(sourceFont, sourceFontPomiconsStart, sourceFontPomiconsEnd, pomicons, symbolsPomiconsRangeStart, symbolsPomiconsRangeEnd, scaleGlyph=symbolsPomiconsScaleGlyph) if args.fontlinux: - copy_glyphs(sourceFont, sourceFontFontLinuxStart, sourceFontFontLinuxEnd, fontlinux, symbolsFontLinuxRangeStart, symbolsFontLinuxRangeEnd, fontlinuxExactEncodingPosition) + copy_glyphs(sourceFont, sourceFontFontLinuxStart, sourceFontFontLinuxEnd, fontlinux, symbolsFontLinuxRangeStart, symbolsFontLinuxRangeEnd, fontlinuxExactEncodingPosition, scaleGlyph=symbolsFontLinuxScaleGlyph) # the `PfEd-comments` flag is required for Fontforge to save # '.comment' and '.fontlog'. From 7e043d633a31049c657d0103c12ad10722e3969e Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 14 Oct 2016 23:37:45 -0700 Subject: [PATCH 07/15] Improved windows naming a bit --- font-patcher | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/font-patcher b/font-patcher index bfa5c6fab..296c30736 100755 --- a/font-patcher +++ b/font-patcher @@ -134,15 +134,14 @@ if subFamily == "Regular": subFamily = fallbackStyle if args.windows: - maxLength = 31 - len('-'+subFamily) + maxFamilyLength = 31 + maxFontLength = maxFamilyLength-len('-' + subFamily) familyname += " " + projectNameAbbreviation fullname += " Windows Compatible" # now make sure less than 32 characters name length - #if len(fullname) > maxLength: - # fullname = fullname[:maxLength] - if len(fontname) > maxLength: + if len(fontname) > maxFontLength: fontname = fontname[:maxLength] - if len(fullname) > maxLength: + if len(familyname) > maxFamilyLength: familyname = familyname[:maxLength] else: familyname += " " + projectNameSingular From af0a9eb8317753c6cb21dbae9b9a0b3f26f8cb95 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Sat, 15 Oct 2016 00:27:40 -0700 Subject: [PATCH 08/15] Add some overlap on separators --- font-patcher | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/font-patcher b/font-patcher index 296c30736..65a7cc1b3 100755 --- a/font-patcher +++ b/font-patcher @@ -100,7 +100,7 @@ if args.fontawesome and args.octicons and args.pomicons and args.powerlineextra # add mono signifier to end of name if args.single: additionalFontNameSuffix += " M" - verboseAdditionalFontNameSuffix += " M" + verboseAdditionalFontNameSuffix += " Mono" sourceFont = fontforge.open(args.font) @@ -140,9 +140,9 @@ if args.windows: fullname += " Windows Compatible" # now make sure less than 32 characters name length if len(fontname) > maxFontLength: - fontname = fontname[:maxLength] + fontname = fontname[:maxFontLength] if len(familyname) > maxFamilyLength: - familyname = familyname[:maxLength] + familyname = familyname[:maxFamilyLength] else: familyname += " " + projectNameSingular @@ -304,34 +304,34 @@ SYM_ATTR = { # Powerline dividers # Arrow tips - 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, # Rounded arcs - 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, # Bottom Triangles - 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, # Top Triangles - 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, # Flames - 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, - 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, # Small squares 0xe0c4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, @@ -354,8 +354,8 @@ SYM_ATTR = { 0xe0d1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, # Top and bottom trapezoid - 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, + 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, } SYM_ATTR_DEFAULT = { From aca83afe12d497aff4dd8122cf041286b4bfec9c Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Sun, 16 Oct 2016 19:48:19 -0700 Subject: [PATCH 09/15] Set overlap at 1% in both h & v directions --- font-patcher | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/font-patcher b/font-patcher index 65a7cc1b3..7dc2a1449 100755 --- a/font-patcher +++ b/font-patcher @@ -363,9 +363,20 @@ SYM_ATTR_DEFAULT = { 'align': 'c', 'stretch': 'pa', 'overlap': False } +# win_ascent and win_descent are used to set the line height for windows fonts. +# hhead_ascent and hhead_descent are used to set the line height for mac fonts. +# +# Make the total line size even. This seems to make the powerline separators +# center more evenly. +if (sourceFont.os2_winascent + sourceFont.os2_windescent) % 2 != 0: + sourceFont.os2_winascent += 1 + +# Make the line size identical for windows and mac +sourceFont.hhea_ascent = sourceFont.os2_winascent +sourceFont.hhea_descent = -sourceFont.os2_windescent + # Initial font dimensions font_dim = { - # Use os2_winXXXXXX for ymin and ymax as this is typically what is used for line size 'xmin' : 0, 'ymin' : -sourceFont.os2_windescent, 'xmax' : 0, @@ -374,25 +385,19 @@ font_dim = { 'height': 0, } -# Find the biggest char width and height +# Find the biggest char width +# Ignore the y-values, os2_winXXXXX values set above are used for line height # # 0x00-0x17f is the Latin Extended-A range -# 0x2500-0x2600 is the box drawing range -for glyph in range(0x00, 0x17f) + range(0x2500, 0x2600): +for glyph in range(0x00, 0x17f): try: (xmin, ymin, xmax, ymax) = sourceFont[glyph].boundingBox() except TypeError: continue - if font_dim['width'] == 0: - font_dim['width'] = sourceFont[glyph].width - if font_dim['width'] < sourceFont[glyph].width: font_dim['width'] = sourceFont[glyph].width - # Ignore the y-values, os2_winXXXXX values set above are more accurate - # if ymin < font_dim['ymin']: font_dim['ymin'] = ymin - # if ymax > font_dim['ymax']: font_dim['ymax'] = ymax if xmax > font_dim['xmax']: font_dim['xmax'] = xmax # Calculate font height @@ -423,14 +428,16 @@ def set_width(sourceFont, width): glyph.width = width def get_scale_factor(font_dim, sym_dim): + scale_ratio = 1 # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit scale_ratio_x = font_dim['width'] / sym_dim['width'] # font_dim['height'] represents total line height, keep our symbols sized based upon font's em scale_ratio_y = sourceFont.em / sym_dim['height'] if scale_ratio_x > scale_ratio_y: - return scale_ratio_y + scale_ratio = scale_ratio_y else: - return scale_ratio_x + scale_ratio = scale_ratio_x + return scale_ratio def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False, scaleGlyph=None): @@ -546,19 +553,23 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # Right align x_align_distance += font_dim['width'] - sym_dim['width'] - align_matrix = psMat.translate(x_align_distance, y_align_distance) - sourceFont.transform(align_matrix) - if sym_attr['overlap'] is True: - overlap_width = sourceFont.em / 48 + # We will use 1% of the font height/width as the overlap amount + overlap_width = font_dim['width'] / 100; + overlap_height = font_dim['height'] / 100; - # Stretch the glyph slightly horizontally if it should overlap - sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], 1)) + sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], + (sym_dim['height'] + overlap_height) / sym_dim['height'] )) + # We are always vertically centering the glyph, so adjust it after the scale operation + y_align_distance -= overlap_height if sym_attr['align'] == 'l': # The glyph should be left-aligned, so it must be moved overlap_width to the left # This only applies to left-aligned glyphs because the glyph is scaled to the right - sourceFont.transform(psMat.translate(-overlap_width, 0)) + x_align_distance -= overlap_width + + align_matrix = psMat.translate(x_align_distance, y_align_distance) + sourceFont.transform(align_matrix) if args.single: # Ensure the font is considered monospaced on Windows by setting the same From 55395910bd25d2ad8143b3221cda1b47f584420c Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Mon, 17 Oct 2016 15:07:39 -0700 Subject: [PATCH 10/15] maximize glyph size for power line and pomicons --- font-patcher | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/font-patcher b/font-patcher index 7dc2a1449..5ca3fb18c 100755 --- a/font-patcher +++ b/font-patcher @@ -281,9 +281,9 @@ sourceFontFontLinuxEnd = 0xF315 # To keep the size of glyphs constant when scaling, choose a larger # sized glyph from each symbol font to set the scaling amount -symbolsPomiconsScaleGlyph = 0xE000 # first symbol -symbolsPowerlineScaleGlyph = 0xE0A0 # scm branch symbol -symbolsPowerlineExtraScaleGlyph = 0xE70E # Android logo +symbolsPomiconsScaleGlyph = None # 0xE000 # first symbol +symbolsPowerlineScaleGlyph = None # 0xE0A0 # scm branch symbol +symbolsPowerlineExtraScaleGlyph = None # 0xE70E # Android logo symbolsDeviconsScaleGlyph = 0xE60E # Android logo symbolsFontAwesomeScaleGlyph = 0xF17A # Windows logo symbolsOcticonsScaleGlyph = 0xF02E # magnifying glass From 8ddf5376ac95fc4132d12af963d6f4c2e3c79f32 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Thu, 20 Oct 2016 15:23:14 -0700 Subject: [PATCH 11/15] Refactored to use patch table --- font-patcher | 146 ++++++++++++--------------------------------------- 1 file changed, 33 insertions(+), 113 deletions(-) diff --git a/font-patcher b/font-patcher index 5ca3fb18c..71e06aadf 100755 --- a/font-patcher +++ b/font-patcher @@ -186,108 +186,32 @@ sourceFont.fontlog = projectInfo + "\n\n" + changelog.read() sourceFont.version += ";" + projectName + " " + version #print "Version now is " + sourceFont.version -# Open fonts and force the em size to be equal - -symbols = fontforge.open("glyph-source-fonts/original-source.otf") -powerlineSymbols = fontforge.open("glyph-source-fonts/PowerlineSymbols.otf") -powerlineExtraSymbols = fontforge.open("glyph-source-fonts/PowerlineExtraSymbols.otf") -symbolsDevicons = fontforge.open("glyph-source-fonts/devicons.ttf") - -symbols.em = sourceFont.em -symbolsDevicons.em = sourceFont.em -powerlineSymbols.em = sourceFont.em -powerlineExtraSymbols.em = sourceFont.em - -if args.fontawesome: - fontawesome = fontforge.open("glyph-source-fonts/FontAwesome.otf") - fontawesome.em = sourceFont.em - -if args.octicons: - octicons = fontforge.open("glyph-source-fonts/octicons.ttf") - octicons.em = sourceFont.em - octiconsExactEncodingPosition = True - -if args.pomicons: - pomicons = fontforge.open("glyph-source-fonts/Pomicons.otf") - pomicons.em = sourceFont.em - -if args.fontlinux: - fontlinux = fontforge.open("glyph-source-fonts/font-linux.ttf") - fontlinux.em = sourceFont.em - fontlinuxExactEncodingPosition = True - # Prevent glyph encoding position conflicts between glyph sets +octiconsExactEncodingPosition = True if args.fontawesome and args.octicons: octiconsExactEncodingPosition = False +fontlinuxExactEncodingPosition = True if args.fontawesome or args.octicons: fontlinuxExactEncodingPosition = False # Define the character ranges # Symbol font ranges -symbolsPomiconsRangeStart = 0xE000 -symbolsPomiconsRangeEnd = 0xE00A - -symbolsPowerlineRange1Start = 0xE0A0 -symbolsPowerlineRange1End = 0xE0A2 - -symbolsPowerlineRange2Start = 0xE0B0 -symbolsPowerlineRange2End = 0xE0B3 - -symbolsPowerlineExtraRange1Start = 0xE0A3 -symbolsPowerlineExtraRange1End = 0xE0A3 - -symbolsPowerlineExtraRange2Start = 0xE0B4 -symbolsPowerlineExtraRange2End = 0xE0C8 - -symbolsPowerlineExtraRange3Start = 0xE0CC -symbolsPowerlineExtraRange3End = 0xE0D4 - -symbolsOriginalRangeStart = 0xE4FA -symbolsOriginalRangeEnd = 0xE52A - -symbolsDeviconsRangeStart = 0xE600 -symbolsDeviconsRangeEnd = 0xE6C5 - -symbolsFontAwesomeRangeStart = 0xF000 -symbolsFontAwesomeRangeEnd = 0xF295 - -symbolsOcticonsRangeStart = 0xF000 -symbolsOcticonsRangeEnd = 0xF0DB - -symbolsFontLinuxRangeStart = 0xF100 -symbolsFontLinuxRangeEnd = 0xF115 - -# Destination font ranges -sourceFontPomiconsStart = 0xE000 -sourceFontPomiconsEnd = 0xE00A - -sourceFontOriginalStart = 0xE5FA -sourceFontOriginalEnd = 0xE62A - -sourceFontDeviconsStart = 0xE700 -sourceFontDeviconsEnd = 0xE7C5 - -sourceFontFontAwesomeStart = 0xF000 -sourceFontFontAwesomeEnd = 0xF295 - -sourceFontOcticonsStart = 0xF400 -sourceFontOcticonsEnd = 0xF4DB - -sourceFontFontLinuxStart = 0xF300 -sourceFontFontLinuxEnd = 0xF315 - -# To keep the size of glyphs constant when scaling, choose a larger -# sized glyph from each symbol font to set the scaling amount -symbolsPomiconsScaleGlyph = None # 0xE000 # first symbol -symbolsPowerlineScaleGlyph = None # 0xE0A0 # scm branch symbol -symbolsPowerlineExtraScaleGlyph = None # 0xE70E # Android logo -symbolsDeviconsScaleGlyph = 0xE60E # Android logo -symbolsFontAwesomeScaleGlyph = 0xF17A # Windows logo -symbolsOcticonsScaleGlyph = 0xF02E # magnifying glass -symbolsFontLinuxScaleGlyph = 0xF10E # Ubuntu logo +PATCH_SET = [ + { 'Enabled': True, 'Filename': "original-source.otf", 'Exact': True, 'SymStart': 0xE4FA, 'SymEnd': 0xE52A, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE62A, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': True, 'Filename': "devicons.ttf", 'Exact': True, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'SrcEnd': 0xE7C5, 'ScaleGlyph': 0xE60E }, # Android logo + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': 0xE0A0, 'SrcEnd': 0xF295, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': 0xE0B0, 'SrcEnd': 0xE0B3, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': 0xE0A3, 'SrcEnd': 0xE0A3, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': 0xE0B4, 'SrcEnd': 0xE0C8, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': 0xE0CC, 'SrcEnd': 0xE0D4, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.pomicons, 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': 0xE000, 'SrcEnd': 0xE00A, 'ScaleGlyph': None }, + { 'Enabled': args.fontawesome, 'Filename': "FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF295, 'SrcStart': 0xF000, 'SrcEnd': 0xF295, 'ScaleGlyph': 0xF17A }, # Windows logo + { 'Enabled': args.fontlinux, 'Filename': "font-linux.ttf", 'Exact': fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF115, 'SrcStart': 0xF300, 'SrcEnd': 0xF315, 'ScaleGlyph': 0xF10E }, # Ubuntu logo + { 'Enabled': args.octicons, 'Filename': "octicons.ttf", 'Exact': octiconsExactEncodingPosition, 'SymStart': 0xF000, 'SymEnd': 0xF0DB, 'SrcStart': 0xF400, 'SrcEnd': 0xF4DB, 'ScaleGlyph': 0xF02E }, # Magnifying glass +] SYM_ATTR = { # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly @@ -598,29 +522,25 @@ if args.single and extension == '.ttf': # This is only a problem with ttf files, otf files seem to be okay. set_width(sourceFont, font_dim['width']) -copy_glyphs(sourceFont, sourceFontOriginalStart, sourceFontOriginalEnd, symbols, symbolsOriginalRangeStart, symbolsOriginalRangeEnd) -copy_glyphs(sourceFont, sourceFontDeviconsStart, sourceFontDeviconsEnd, symbolsDevicons, symbolsDeviconsRangeStart, symbolsDeviconsRangeEnd, scaleGlyph=symbolsDeviconsScaleGlyph) +# Prevent opening and closing the fontforge font. Makes things faster when patching +# multiple ranges using the same symbol font. +PreviousSymbolFilename = "" +symfont = None +for patch in PATCH_SET: + if patch['Enabled']: + if PreviousSymbolFilename != patch['Filename']: + # We have a new symbol font, so close the previous one if it exists + if symfont: + symfont.close() + symfont = None + symfont = fontforge.open("glyph-source-fonts/"+patch['Filename']) + # Match the symbol font size to the source font size + symfont.em = sourceFont.em + PreviousSymbolFilename = patch['Filename'] + copy_glyphs(sourceFont, patch['SrcStart'], patch['SrcEnd'], symfont, patch['SymStart'], patch['SymEnd'], patch['Exact'], patch['ScaleGlyph']) -if args.powerline: - copy_glyphs(sourceFont, symbolsPowerlineRange1Start, symbolsPowerlineRange1End, powerlineSymbols, symbolsPowerlineRange1Start, symbolsPowerlineRange1End, scaleGlyph=symbolsPowerlineScaleGlyph) - copy_glyphs(sourceFont, symbolsPowerlineRange2Start, symbolsPowerlineRange2End, powerlineSymbols, symbolsPowerlineRange2Start, symbolsPowerlineRange2End, scaleGlyph=symbolsPowerlineScaleGlyph) - -if args.powerlineextra: - copy_glyphs(sourceFont, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, powerlineExtraSymbols, symbolsPowerlineExtraRange1Start, symbolsPowerlineExtraRange1End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) - copy_glyphs(sourceFont, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, powerlineExtraSymbols, symbolsPowerlineExtraRange2Start, symbolsPowerlineExtraRange2End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) - copy_glyphs(sourceFont, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, powerlineExtraSymbols, symbolsPowerlineExtraRange3Start, symbolsPowerlineExtraRange3End, True, scaleGlyph=symbolsPowerlineExtraScaleGlyph) - -if args.fontawesome: - copy_glyphs(sourceFont, sourceFontFontAwesomeStart, sourceFontFontAwesomeEnd, fontawesome, symbolsFontAwesomeRangeStart, symbolsFontAwesomeRangeEnd, True, scaleGlyph=symbolsFontAwesomeScaleGlyph) - -if args.octicons: - copy_glyphs(sourceFont, sourceFontOcticonsStart, sourceFontOcticonsEnd, octicons, symbolsOcticonsRangeStart, symbolsOcticonsRangeEnd, octiconsExactEncodingPosition, scaleGlyph=symbolsOcticonsScaleGlyph) - -if args.pomicons: - copy_glyphs(sourceFont, sourceFontPomiconsStart, sourceFontPomiconsEnd, pomicons, symbolsPomiconsRangeStart, symbolsPomiconsRangeEnd, scaleGlyph=symbolsPomiconsScaleGlyph) - -if args.fontlinux: - copy_glyphs(sourceFont, sourceFontFontLinuxStart, sourceFontFontLinuxEnd, fontlinux, symbolsFontLinuxRangeStart, symbolsFontLinuxRangeEnd, fontlinuxExactEncodingPosition, scaleGlyph=symbolsFontLinuxScaleGlyph) +if symfont: + symfont.close() # the `PfEd-comments` flag is required for Fontforge to save # '.comment' and '.fontlog'. From b453598dcab6ef6825600a1e2697977d4e6c692e Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Thu, 20 Oct 2016 15:24:45 -0700 Subject: [PATCH 12/15] Removed stale comments --- font-patcher | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/font-patcher b/font-patcher index 71e06aadf..48c6f5ed6 100755 --- a/font-patcher +++ b/font-patcher @@ -200,13 +200,13 @@ if args.fontawesome or args.octicons: # Symbol font ranges PATCH_SET = [ - { 'Enabled': True, 'Filename': "original-source.otf", 'Exact': True, 'SymStart': 0xE4FA, 'SymEnd': 0xE52A, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE62A, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': True, 'Filename': "original-source.otf", 'Exact': True, 'SymStart': 0xE4FA, 'SymEnd': 0xE52A, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE62A, 'ScaleGlyph': None }, { 'Enabled': True, 'Filename': "devicons.ttf", 'Exact': True, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'SrcEnd': 0xE7C5, 'ScaleGlyph': 0xE60E }, # Android logo - { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': 0xE0A0, 'SrcEnd': 0xF295, 'ScaleGlyph': None }, # Windows logo - { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': 0xE0B0, 'SrcEnd': 0xE0B3, 'ScaleGlyph': None }, # Windows logo - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': 0xE0A3, 'SrcEnd': 0xE0A3, 'ScaleGlyph': None }, # Windows logo - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': 0xE0B4, 'SrcEnd': 0xE0C8, 'ScaleGlyph': None }, # Windows logo - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': 0xE0CC, 'SrcEnd': 0xE0D4, 'ScaleGlyph': None }, # Windows logo + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': 0xE0A0, 'SrcEnd': 0xF295, 'ScaleGlyph': None }, + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': 0xE0B0, 'SrcEnd': 0xE0B3, 'ScaleGlyph': None }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': 0xE0A3, 'SrcEnd': 0xE0A3, 'ScaleGlyph': None }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': 0xE0B4, 'SrcEnd': 0xE0C8, 'ScaleGlyph': None }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': 0xE0CC, 'SrcEnd': 0xE0D4, 'ScaleGlyph': None }, { 'Enabled': args.pomicons, 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': 0xE000, 'SrcEnd': 0xE00A, 'ScaleGlyph': None }, { 'Enabled': args.fontawesome, 'Filename': "FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF295, 'SrcStart': 0xF000, 'SrcEnd': 0xF295, 'ScaleGlyph': 0xF17A }, # Windows logo { 'Enabled': args.fontlinux, 'Filename': "font-linux.ttf", 'Exact': fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF115, 'SrcStart': 0xF300, 'SrcEnd': 0xF315, 'ScaleGlyph': 0xF10E }, # Ubuntu logo From 7e1ff32cd4aa642a8725dcc83903e268ce6144a8 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Thu, 20 Oct 2016 20:07:56 -0700 Subject: [PATCH 13/15] Fixed bug in careful option that was checking wrong slot due to hex to dec conversion error --- font-patcher | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/font-patcher b/font-patcher index 48c6f5ed6..d0a8f1536 100755 --- a/font-patcher +++ b/font-patcher @@ -392,7 +392,8 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo if exactEncoding: # use the exact same hex values for the source font as for the symbol font currentSourceFontGlyph = sym_glyph.encoding - copiedToSlot = str(sym_glyph.unicode) + # Save as a hex string without the '0x' prefix + copiedToSlot = format(sym_glyph.unicode, 'X') else: # use source font defined hex values based on passed in start and end # convince that this string really is a hex: @@ -400,7 +401,7 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo copiedToSlot = sourceFontList[sourceFontCounter] if args.quiet == False: - print "updating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + str(copiedToSlot) + print "Updating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + copiedToSlot # Prepare symbol glyph dimensions sym_dim = get_dim(sym_glyph) @@ -418,6 +419,8 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo codepoint = int("0x" + copiedToSlot, 16) try: sourceFont[codepoint] + if args.quiet == False: + print " Found existing Glyph. Skipping..." except TypeError: # nothing there go ahead and paste at this codepoint sourceFont.selection.select(currentSourceFontGlyph) From 1edd4ca9d277ec7bddeccd74aff7310b300fe672 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 21 Oct 2016 21:59:40 -0700 Subject: [PATCH 14/15] Fixed final issues with careful mode, parameterized overlap. --- font-patcher | 206 +++++++++++++++++++++++++-------------------------- 1 file changed, 102 insertions(+), 104 deletions(-) diff --git a/font-patcher b/font-patcher index d0a8f1536..ef1cc2945 100755 --- a/font-patcher +++ b/font-patcher @@ -196,97 +196,89 @@ fontlinuxExactEncodingPosition = True if args.fontawesome or args.octicons: fontlinuxExactEncodingPosition = False -# Define the character ranges -# Symbol font ranges +# Supported params: overlap | careful -PATCH_SET = [ - { 'Enabled': True, 'Filename': "original-source.otf", 'Exact': True, 'SymStart': 0xE4FA, 'SymEnd': 0xE52A, 'SrcStart': 0xE5FA, 'SrcEnd': 0xE62A, 'ScaleGlyph': None }, - { 'Enabled': True, 'Filename': "devicons.ttf", 'Exact': True, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'SrcEnd': 0xE7C5, 'ScaleGlyph': 0xE60E }, # Android logo - { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': 0xE0A0, 'SrcEnd': 0xF295, 'ScaleGlyph': None }, - { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': 0xE0B0, 'SrcEnd': 0xE0B3, 'ScaleGlyph': None }, - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': 0xE0A3, 'SrcEnd': 0xE0A3, 'ScaleGlyph': None }, - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': 0xE0B4, 'SrcEnd': 0xE0C8, 'ScaleGlyph': None }, - { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': 0xE0CC, 'SrcEnd': 0xE0D4, 'ScaleGlyph': None }, - { 'Enabled': args.pomicons, 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': 0xE000, 'SrcEnd': 0xE00A, 'ScaleGlyph': None }, - { 'Enabled': args.fontawesome, 'Filename': "FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF295, 'SrcStart': 0xF000, 'SrcEnd': 0xF295, 'ScaleGlyph': 0xF17A }, # Windows logo - { 'Enabled': args.fontlinux, 'Filename': "font-linux.ttf", 'Exact': fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF115, 'SrcStart': 0xF300, 'SrcEnd': 0xF315, 'ScaleGlyph': 0xF10E }, # Ubuntu logo - { 'Enabled': args.octicons, 'Filename': "octicons.ttf", 'Exact': octiconsExactEncodingPosition, 'SymStart': 0xF000, 'SymEnd': 0xF0DB, 'SrcStart': 0xF400, 'SrcEnd': 0xF4DB, 'ScaleGlyph': 0xF02E }, # Magnifying glass -] - -SYM_ATTR = { - # Right/left-aligned glyphs will have their advance width reduced in order to overlap the next glyph slightly - 0x2b60: { 'align': 'c', 'stretch': 'y' , 'overlap': False }, - 0x2b61: { 'align': 'c', 'stretch': '' , 'overlap': False }, - 0x2b62: { 'align': 'r', 'stretch': '' , 'overlap': False }, - 0x2b63: { 'align': 'l', 'stretch': '' , 'overlap': False }, - 0x2b64: { 'align': 'c', 'stretch': '' , 'overlap': False }, - 0x2b80: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0x2b81: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0x2b82: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0x2b83: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - - # Powerline dividers +# Powerline dividers +SYM_ATTR_POWERLINE = { + 'default': { 'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': '' }, # Arrow tips - 0xe0b0: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0b1: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0b2: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0xe0b3: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0b0: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0b1: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0b2: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0b3: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, # Rounded arcs - 0xe0b4: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0b5: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0b6: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0xe0b7: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0b4: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0b5: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0b6: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0b7: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, # Bottom Triangles - 0xe0b8: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0b9: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0ba: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0xe0bb: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0b8: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0b9: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0ba: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0bb: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, # Top Triangles - 0xe0bc: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0bd: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0be: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0xe0bf: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0bc: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0bd: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0be: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0bf: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, # Flames - 0xe0c0: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0c1: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0c2: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, - 0xe0c3: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0c0: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0c1: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0c2: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, + 0xe0c3: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, # Small squares - 0xe0c4: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c5: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0c4: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': '' }, + 0xe0c5: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': '' }, # Bigger squares - 0xe0c6: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0c7: { 'align': 'r', 'stretch': 'xy', 'overlap': False }, + 0xe0c6: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': '' }, + 0xe0c7: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': '' }, # Waveform - 0xe0c8: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0c8: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.01} }, # Hexagons - 0xe0cc: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0cd: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0cc: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': '' }, + 0xe0cd: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': '' }, # Legos - 0xe0ce: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, - 0xe0cf: { 'align': 'c', 'stretch': 'xy', 'overlap': False }, - 0xe0d1: { 'align': 'l', 'stretch': 'xy', 'overlap': False }, + 0xe0ce: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': '' }, + 0xe0cf: { 'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': '' }, + 0xe0d1: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, # Top and bottom trapezoid - 0xe0d2: { 'align': 'l', 'stretch': 'xy', 'overlap': True }, - 0xe0d4: { 'align': 'r', 'stretch': 'xy', 'overlap': True }, + 0xe0d2: { 'align': 'l', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, + 0xe0d4: { 'align': 'r', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap':0.02} }, } SYM_ATTR_DEFAULT = { # 'pa' == preserve aspect ratio - 'align': 'c', 'stretch': 'pa', 'overlap': False + 'default': { 'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': '' }, } +# Define the character ranges +# Symbol font ranges + +PATCH_SET = [ + { 'Enabled': True, 'Filename': "original-source.otf", 'Exact': False,'SymStart': 0xE4FA, 'SymEnd': 0xE52A, 'SrcStart': 0xE5FA,'SrcEnd': 0xE62A,'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT }, + { 'Enabled': True, 'Filename': "devicons.ttf", 'Exact': False,'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700,'SrcEnd': 0xE7C5,'ScaleGlyph': 0xE60E,'Attributes': SYM_ATTR_DEFAULT }, # Android logo + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE }, + { 'Enabled': args.powerline, 'Filename': "PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE }, + { 'Enabled': args.powerlineextra, 'Filename': "PowerlineExtraSymbols.otf",'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D4, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_POWERLINE }, + { 'Enabled': args.pomicons, 'Filename': "Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': None, 'Attributes': SYM_ATTR_DEFAULT }, + { 'Enabled': args.fontawesome, 'Filename': "FontAwesome.otf", 'Exact': True, 'SymStart': 0xF000, 'SymEnd': 0xF295, 'SrcStart': None, 'SrcEnd': None, 'ScaleGlyph': 0xF17A,'Attributes': SYM_ATTR_DEFAULT }, # Windows logo + { 'Enabled': args.fontlinux, 'Filename': "font-linux.ttf", 'Exact': fontlinuxExactEncodingPosition, 'SymStart': 0xF100, 'SymEnd': 0xF115, 'SrcStart': 0xF300, 'SrcEnd': 0xF315, 'ScaleGlyph': 0xF10E, 'Attributes': SYM_ATTR_DEFAULT }, # Ubuntu logo + { 'Enabled': args.octicons, 'Filename': "octicons.ttf", 'Exact': octiconsExactEncodingPosition, 'SymStart': 0xF000, 'SymEnd': 0xF0DB, 'SrcStart': 0xF400, 'SrcEnd': 0xF4DB, 'ScaleGlyph': 0xF02E, 'Attributes': SYM_ATTR_DEFAULT }, # Magnifying glass +] + # win_ascent and win_descent are used to set the line height for windows fonts. # hhead_ascent and hhead_descent are used to set the line height for mac fonts. # @@ -363,7 +355,7 @@ def get_scale_factor(font_dim, sym_dim): scale_ratio = scale_ratio_x return scale_ratio -def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding=False, scaleGlyph=None): +def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding, scaleGlyph, attributes): if exactEncoding is False: sourceFontList = [] @@ -383,11 +375,9 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo for sym_glyph in symbolFont.selection.byGlyphs: try: - sym_attr = SYM_ATTR[sym_glyph.unicode] + sym_attr = attributes[sym_glyph.unicode] except KeyError: - sym_attr = SYM_ATTR_DEFAULT - - glyphName = sym_glyph.glyphname + sym_attr = attributes['default'] if exactEncoding: # use the exact same hex values for the source font as for the symbol font @@ -399,6 +389,7 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # convince that this string really is a hex: currentSourceFontGlyph = int("0x" + sourceFontList[sourceFontCounter], 16) copiedToSlot = sourceFontList[sourceFontCounter] + sourceFontCounter += 1 if args.quiet == False: print "Updating glyph: " + str(sym_glyph) + " " + str(sym_glyph.glyphname) + " putting at: " + copiedToSlot @@ -406,30 +397,30 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # Prepare symbol glyph dimensions sym_dim = get_dim(sym_glyph) - # Select and copy symbol from its encoding point - symbolFont.selection.select(sym_glyph.encoding) - symbolFont.copy() - - # check it - if args.careful: + # check if a glyph already exists in this location + if args.careful or 'careful' in sym_attr['params']: if copiedToSlot.startswith("uni"): copiedToSlot = copiedToSlot[3:] codepoint = int("0x" + copiedToSlot, 16) - try: - sourceFont[codepoint] + if codepoint in sourceFont: if args.quiet == False: - print " Found existing Glyph. Skipping..." - except TypeError: - # nothing there go ahead and paste at this codepoint - sourceFont.selection.select(currentSourceFontGlyph) - sourceFont.paste() - else: - sourceFont.selection.select(currentSourceFontGlyph) - sourceFont.paste() + print " Found existing Glyph at "+ copiedToSlot +". Skipping..." + # We don't want to touch anything so move to next Glyph + continue - sourceFont[currentSourceFontGlyph].glyphname = glyphName + # Select and copy symbol from its encoding point + # We need to do this select after the careful check, this way we don't + # reset our selection before starting the next loop + symbolFont.selection.select(sym_glyph.encoding) + symbolFont.copy() + + # Paste it + sourceFont.selection.select(currentSourceFontGlyph) + sourceFont.paste() + + sourceFont[currentSourceFontGlyph].glyphname = sym_glyph.glyphname # Now that we have copy/pasted the glyph, if we are creating a monospace # font we need to scale and move the glyphs. It is possible to have @@ -464,26 +455,29 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # Use the dimensions from the newly pasted and stretched glyph sym_dim = get_dim(sourceFont[currentSourceFontGlyph]) - # Center the symbol vertically by matching the center of the line height and center of symbol - sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) - font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) - y_align_distance = font_ycenter - sym_ycenter + y_align_distance = 0 + if sym_attr['valign'] == 'c': + # Center the symbol vertically by matching the center of the line height and center of symbol + sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) + font_ycenter = font_dim['ymax'] - (font_dim['height'] / 2) + y_align_distance = font_ycenter - sym_ycenter # Handle glyph l/r/c alignment + x_align_distance = 0 + if sym_attr['align']: + # First find the baseline x-alignment (left alignment amount) + x_align_distance = font_dim['xmin']-sym_dim['xmin'] + if sym_attr['align'] == 'c': + # Center align + x_align_distance += (font_dim['width']/2) - (sym_dim['width']/2) + elif sym_attr['align'] == 'r': + # Right align + x_align_distance += font_dim['width'] - sym_dim['width'] - # First find the baseline x-alignment (left alignment amount) - x_align_distance = font_dim['xmin']-sym_dim['xmin'] - if sym_attr['align'] == 'c': - # Center align - x_align_distance += (font_dim['width']/2) - (sym_dim['width']/2) - elif sym_attr['align'] == 'r': - # Right align - x_align_distance += font_dim['width'] - sym_dim['width'] - - if sym_attr['overlap'] is True: + if 'overlap' in sym_attr['params']: # We will use 1% of the font height/width as the overlap amount - overlap_width = font_dim['width'] / 100; - overlap_height = font_dim['height'] / 100; + overlap_width = font_dim['width'] * sym_attr['params']['overlap'] + overlap_height = font_dim['height'] * sym_attr['params']['overlap'] sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], (sym_dim['height'] + overlap_height) / sym_dim['height'] )) @@ -505,9 +499,6 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo # didn't go through the scaling operations. sourceFont[currentSourceFontGlyph].width = font_dim['width'] - if exactEncoding is False: - sourceFontCounter += 1 - # reset selection so iteration works propertly @todo fix? rookie misunderstanding? # This is likely needed because the selection was changed when the glyph was copy/pasted symbolFont.selection.select(("ranges","unicode"),symbolFontStart,symbolFontEnd) @@ -540,7 +531,14 @@ for patch in PATCH_SET: # Match the symbol font size to the source font size symfont.em = sourceFont.em PreviousSymbolFilename = patch['Filename'] - copy_glyphs(sourceFont, patch['SrcStart'], patch['SrcEnd'], symfont, patch['SymStart'], patch['SymEnd'], patch['Exact'], patch['ScaleGlyph']) + # If patch table doesn't include a source start and end, re-use the symbol font values + SrcStart = patch['SrcStart'] + SrcEnd = patch['SrcEnd'] + if not SrcStart: + SrcStart = patch['SymStart'] + if not SrcEnd: + SrcEnd = patch['SymEnd'] + copy_glyphs(sourceFont, SrcStart, SrcEnd, symfont, patch['SymStart'], patch['SymEnd'], patch['Exact'], patch['ScaleGlyph'], patch['Attributes']) if symfont: symfont.close() From 994267d94c921f05eb0a9886df38b0972a785d08 Mon Sep 17 00:00:00 2001 From: Marcus Kellerman Date: Fri, 21 Oct 2016 23:26:03 -0700 Subject: [PATCH 15/15] Fix overlap (noticable with large amounts) --- font-patcher | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/font-patcher b/font-patcher index ef1cc2945..41bc997d2 100755 --- a/font-patcher +++ b/font-patcher @@ -450,6 +450,9 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo scale_ratio_y = font_dim['height'] / sym_dim['height'] if scale_ratio_x != 1 or scale_ratio_y != 1: + if 'overlap' in sym_attr['params']: + scale_ratio_x *= 1+sym_attr['params']['overlap'] + scale_ratio_y *= 1+sym_attr['params']['overlap'] sourceFont.transform(psMat.scale(scale_ratio_x, scale_ratio_y)) # Use the dimensions from the newly pasted and stretched glyph @@ -475,19 +478,11 @@ def copy_glyphs(sourceFont, sourceFontStart, sourceFontEnd, symbolFont, symbolFo x_align_distance += font_dim['width'] - sym_dim['width'] if 'overlap' in sym_attr['params']: - # We will use 1% of the font height/width as the overlap amount overlap_width = font_dim['width'] * sym_attr['params']['overlap'] - overlap_height = font_dim['height'] * sym_attr['params']['overlap'] - - sourceFont.transform(psMat.scale((sym_dim['width'] + overlap_width) / sym_dim['width'], - (sym_dim['height'] + overlap_height) / sym_dim['height'] )) - - # We are always vertically centering the glyph, so adjust it after the scale operation - y_align_distance -= overlap_height if sym_attr['align'] == 'l': - # The glyph should be left-aligned, so it must be moved overlap_width to the left - # This only applies to left-aligned glyphs because the glyph is scaled to the right x_align_distance -= overlap_width + if sym_attr['align'] == 'r': + x_align_distance += overlap_width align_matrix = psMat.translate(x_align_distance, y_align_distance) sourceFont.transform(align_matrix)