Skip to content

Commit

Permalink
Adding useful scripts for Glyphs font editor.
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Spreadbury committed Feb 16, 2019
1 parent 74db8e3 commit 96f269c
Show file tree
Hide file tree
Showing 8 changed files with 513 additions and 0 deletions.
14 changes: 14 additions & 0 deletions scripts/glyphsapp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
For these scripts to work, you'll need to put three SMuFL metadata files into the same folder as the scripts:

- bravura_metadata.json
- glyphnames.json
- ranges.json

**Important note: these scripts will modify your Glyphs project / font file so it's critical to have backups before running any operations. While I've tested the scripts here, I cannot guarantee that it will work in every single situation.**

Now I've got the disclaimer out of the way, the first thing to run is the "Set metadata.." script. You should see all your glyphs coloured and categorised. If you then run the "Set Glyph names to SMuFL names" it should sort them into the categories. You can switch between SMuFL names, descriptions and codepoints using these three scripts. My understanding is that you should run the "Set Glyph names to codepoints" before doing a final export of your font file for maximum compatibility with various applications which expect the glyph names to correspond to the codepoint.

Once the metadata is set on the glyphs, the "generate_font_metadata.py" script should work as expected.

There's one more extra script which is called "Populate ranges". If you select one or more glyphs and run this script, it will create any other missing glyphs from that range as empty glyphs. You can also edit the script and uncomment or edit the DEFAULT_RANGES_TO_POPULATE array with the range you'd like to create. Running the script with no glyphs selected will create the default ranges from this list.

98 changes: 98 additions & 0 deletions scripts/glyphsapp/generate_font_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#MenuTitle: Generate SMuFL metadata JSON (Anchors + BBoxes)
# -*- coding: utf-8 -*-
# SMuFL metadata generator for Glyohs
# The script should be added to Glyphs scripts folder
#
# By default it will output the metadata file onto the user's desktop, but this can be changed
# by adjusting the value of the OUTPUT_DIR variable.
#
# Features currently supported:
# - engraving defaults
# - bounding boxes
# - anchors
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!

import json
import os
from time import gmtime, strftime

OUTPUT_DIR = os.path.join( os.path.expanduser("~"), "Desktop" )

currentFont = Glyphs.font

# The values in the dictionary below should be manually edited
font_metadata = {
"fontName": currentFont.familyName,
"fontVersion": 1.12,
"engravingDefaults": {
"arrowShaftThickness": 0.16,
"barlineSeparation": 0.4,
"beamSpacing": 0.25,
"beamThickness": 0.5,
"bracketThickness": 0.5,
"dashedBarlineDashLength": 0.5,
"dashedBarlineGapLength": 0.25,
"dashedBarlineThickness": 0.16,
"hairpinThickness": 0.16,
"legerLineExtension": 0.4,
"legerLineThickness": 0.16,
"lyricLineThickness": 0.16,
"octaveLineThickness": 0.16,
"pedalLineThickness": 0.16,
"repeatBarlineDotSeparation": 0.16,
"repeatEndingLineThickness": 0.16,
"slurEndpointThickness": 0.1,
"slurMidpointThickness": 0.22,
"staffLineThickness": 0.13,
"stemThickness": 0.12,
"subBracketThickness": 0.16,
"textEnclosureThickness": 0.16,
"thickBarlineThickness": 0.5,
"thinBarlineThickness": 0.16,
"tieEndpointThickness": 0.1,
"tieMidpointThickness": 0.22,
"tupletBracketThickness": 0.16
},
"glyphsWithAnchors": {},
"glyphBBoxes": {},
"optionalGlyphs": {}}


metadata_filename = os.path.join(OUTPUT_DIR, "%s_metadata_%s.json" % ( currentFont.familyName,
strftime( "%Y%m%d_%H%M%S", gmtime() ) ) )

print "Writing metadata to: %s" % metadata_filename

def to_cartesian(val):
return float(val)/250

for g in currentFont.glyphs:
if len(g.layers) != 1:
print g, len(g.layers)

layer = g.layers[0]

glyph_name = g.userData['name']
font_metadata["glyphBBoxes"][glyph_name] = \
{"bBoxSW": [
to_cartesian(layer.bounds.origin.x),
to_cartesian(layer.bounds.origin.y)
],
"bBoxNE": [
to_cartesian(layer.bounds.origin.x + layer.bounds.size.width),
to_cartesian(layer.bounds.origin.y + layer.bounds.size.height)
]
}
if len(layer.anchors) > 0:
font_metadata['glyphsWithAnchors'][glyph_name] = {}

for anchor in layer.anchors:
font_metadata['glyphsWithAnchors'][glyph_name][anchor.name] = \
[to_cartesian(anchor.position.x), to_cartesian(anchor.position.y)]

with open(metadata_filename, 'w') as outfile:
json.dump(font_metadata, outfile, indent=True, sort_keys=True)

print "Done..."
99 changes: 99 additions & 0 deletions scripts/glyphsapp/populate_ranges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env python
#MenuTitle: Populate ranges
# -*- coding: utf-8 -*-
#
# If you have one or more glyphs selected in given ranges, it will ensure that
# all the rest of the glyphs from those ranges are created.
#
# Note: it will default to setting the display name of newly created glyphs to
# the codepoint. This can be easily remedied by running one of the "set display
# name scripts".
#
# If the script is invoked with no selection it will populate the default ranges
# that are uncommented below.
#
# The script should be added to Glyphs scripts folder and expects the following
# SMuFL and Bravura metadata files to be present in the same directory.
#
# - bravura_metadata.json
# - glyphnames.json
# - ranges.json
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!
#
__doc__="""
"""

import sys
from smufl_glyphs import SMuFLFontSyncer, invoke_menu_item

# Uncomment any ranges that you'd like to be populated when nothing is selected.
DEFAULT_RANGES_TO_POPULATE = [
# u'articulation',
# u'articulationSupplement',
# u'barlines',
# u'barRepeats',
# u'beamedGroupsOfNotes',
# u'beamsAndSlurs',
# u'chordSymbols',
# u'clefs',
# u'clefsSupplement',
# u'commonOrnaments',
# u'dynamics',
# u'flags',
# u'holdsAndPauses',
# u'individualNotes',
# u'lyrics',
# u'miscellaneousSymbols',
# u'multiSegmentLines',
# u'noteheads',
# u'noteNameNoteheads',
# u'octaves',
# u'octavesSupplement',
# u'otherAccidentals',
# u'otherBaroqueOrnaments',
# u'precomposedTrillsAndMordents',
# u'repeats',
# u'rests',
# u'roundAndSquareNoteheads',
# u'shapeNoteNoteheads',
# u'shapeNoteNoteheadsSupplement',
# u'slashNoteheads',
# u'staffBracketsAndDividers',
# u'standardAccidentals12Edo',
# u'standardAccidentalsChordSymbols',
# u'staves',
# u'stems',
# u'stringTechniques',
# u'timeSignatures',
# u'timeSignaturesSupplement',
# u'tremolos',
# u'tuplets',
# u'vocalTechniques',
]

currentFont = Glyphs.font

selected_glyphs = currentFont.selection
if len(selected_glyphs) == 0:
ranges_to_populate = DEFAULT_RANGES_TO_POPULATE
else:
ranges_to_populate = []
for g in selected_glyphs:
range_id = g.userData['smufl_range']
if range_id is not None and range_id not in ranges_to_populate:
ranges_to_populate.append(range_id)

if len(ranges_to_populate) == 0:
print("No ranges to populate")
sys.exit()

smufl_font_syncer = SMuFLFontSyncer(currentFont)
currentFont.disableUpdateInterface()
smufl_font_syncer.populate_ranges(ranges_to_populate)
currentFont.enableUpdateInterface()



39 changes: 39 additions & 0 deletions scripts/glyphsapp/set_display_name_to_codepoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#MenuTitle: Set Glyph names to codepoints
# -*- coding: utf-8 -*-
#
# Set the display name of the selected glyphs to show the codepoint.
# If the script is invoked with no selection it will apply to all glyphs.
#
# NOTE: this should be run before exporting for maximum compatibility with apps
# that expect the glyphs to be named according to their codepoint.
#
# The script should be added to Glyphs scripts folder and expects the following
# SMuFL and Bravura metadata files to be present in the same directory.
#
# - bravura_metadata.json
# - glyphnames.json
# - ranges.json
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!
#
__doc__="""
Set the display name of the glyph to the unicode codepoint
"""

from smufl_glyphs import set_display_name_to, invoke_menu_item, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX

currentFont = Glyphs.font

selected_glyphs = currentFont.selection
if len(selected_glyphs) == 0:
glyphs_to_change = currentFont.glyphs
else:
glyphs_to_change = selected_glyphs

currentFont.disableUpdateInterface()
set_display_name_to(glyphs_to_change, 'uniCodepoint')
currentFont.enableUpdateInterface()
if len(selected_glyphs) == 0:
print ("Deselecting...")
invoke_menu_item(Glyphs, EDIT_MENU, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX)
38 changes: 38 additions & 0 deletions scripts/glyphsapp/set_display_name_to_glyph_description.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#MenuTitle: Set Glyph names to SMuFL descriptions
# -*- coding: utf-8 -*-
#
# Set the display name of the selected glyphs to show the SMuFL description
#
# If the script is invoked with no selection it will apply to all glyphs.
#
# The script should be added to Glyphs scripts folder and expects the following
# SMuFL and Bravura metadata files to be present in the same directory.
#
# - bravura_metadata.json
# - glyphnames.json
# - ranges.json
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!
#
__doc__="""
Set the display name of the glyph to the description of the glyph
"""

from smufl_glyphs import set_display_name_to, invoke_menu_item, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX

currentFont = Glyphs.font

selected_glyphs = currentFont.selection
if len(selected_glyphs) == 0:
glyphs_to_change = currentFont.glyphs
else:
glyphs_to_change = selected_glyphs

currentFont.disableUpdateInterface()
set_display_name_to(glyphs_to_change, 'description')
currentFont.enableUpdateInterface()
# If there weren't any glyphs selected when this script was invoked, make sure there aren't any afterwards.
if len(selected_glyphs) == 0:
print ("Deselecting...")
invoke_menu_item(Glyphs, EDIT_MENU, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX)
38 changes: 38 additions & 0 deletions scripts/glyphsapp/set_display_name_to_glyph_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#MenuTitle: Set Glyph names to SMuFL names
# -*- coding: utf-8 -*-
#
# Set the display name of the selected glyphs to show the SMuFL glyph name.
#
# NOTE: this should be run before exporting for maximum compatibility with apps
# that expect the glyphs to be named according to their codepoint.
#
# The script should be added to Glyphs scripts folder and expects the following
# SMuFL and Bravura metadata files to be present in the same directory.
#
# - bravura_metadata.json
# - glyphnames.json
# - ranges.json
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!
#
__doc__="""
Set the display name of the glyph to the SMuFL name of the glyph
"""

from smufl_glyphs import set_display_name_to, invoke_menu_item, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX

currentFont = Glyphs.font

selected_glyphs = currentFont.selection
if len(selected_glyphs) == 0:
glyphs_to_change = currentFont.glyphs
else:
glyphs_to_change = selected_glyphs

currentFont.disableUpdateInterface()
set_display_name_to(glyphs_to_change, 'name')
currentFont.enableUpdateInterface()
if len(selected_glyphs) == 0:
print ("Deselecting...")
invoke_menu_item(Glyphs, EDIT_MENU, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX)
42 changes: 42 additions & 0 deletions scripts/glyphsapp/set_metadata_and_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python
#MenuTitle: Set metadata on selected (or all) glyphs, including categorisation
# -*- coding: utf-8 -*-
#
# Set the metadata for all the selected glyphs in the font.
# If the script is invoked with no selection it will apply to all glyphs.
#
# The script should be added to Glyphs scripts folder and expects the following
# SMuFL and Bravura metadata files to be present in the same directory.
#
# - bravura_metadata.json
# - glyphnames.json
# - ranges.json
#
# Written by Ben Timms - Steinberg Media Technologies GmbH 2018
# Use, distribute and edit this script as you wish!
#
__doc__="""
"""

from smufl_glyphs import SMuFLFontSyncer, invoke_menu_item, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX

BRAVURA_METADATA_FILENAME = "bravura_metadata.json"
GLYPHNAMES_FILENAME = "glyphnames.json"
RANGES_FILENAME = "ranges.json"

currentFont = Glyphs.font

selected_glyphs = currentFont.selection
if len(selected_glyphs) == 0:
glyphs_to_change = currentFont.glyphs
else:
glyphs_to_change = selected_glyphs

smufl_font_syncer = SMuFLFontSyncer(currentFont, BRAVURA_METADATA_FILENAME, GLYPHNAMES_FILENAME, RANGES_FILENAME)
currentFont.disableUpdateInterface()
smufl_font_syncer.sync_metadata(glyphs_to_change)
currentFont.enableUpdateInterface()
# If there weren't any glyphs selected when this script was invoked, make sure there aren't any afterwards.
if len(selected_glyphs) == 0:
invoke_menu_item(Glyphs, EDIT_MENU, GLYPHS_EDIT_MENU_DESELECT_ALL_IDX)
Loading

0 comments on commit 96f269c

Please sign in to comment.