Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UFO Rountrip #244

Merged
merged 44 commits into from
Mar 20, 2018
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
aa326c2
Make the roundtrip work on GlyphsUnitTestSans
belluzj Oct 19, 2017
3c29101
Improve the integration test script (Noto, Montserrat and others)
belluzj Nov 22, 2017
03f34d3
Simplify custom params
belluzj Nov 24, 2017
d6e832d
Fix some Glyphs-Glyphs rt issues
belluzj Nov 24, 2017
03ea2c2
Sort out the userData/lib stuff + other fixes
belluzj Dec 7, 2017
f99f83d
Use PLIST for Designspace Document lib
belluzj Dec 13, 2017
0ad00da
Fix the groups + other WIP stuff
belluzj Dec 15, 2017
12b8226
Hide bool vs int diffs from UFO-UFO roundtrip
belluzj Dec 18, 2017
8fcdc2c
Add unit tests for all UFO info fields
belluzj Dec 20, 2017
b869196
Improve roundtrip of feature files
belluzj Jan 9, 2018
f17b111
Improve roundtrip for guidelines and others
belluzj Jan 9, 2018
f8372d0
Add default axis locations to Glyphs masters
belluzj Jan 10, 2018
53433ff
Fix more small roundtrip problems
belluzj Jan 10, 2018
4228ca0
Fix the roundtrip of advance width of background
belluzj Jan 11, 2018
5d09416
Handle double unicodes, see #216
belluzj Jan 11, 2018
9e618d2
Handle Mac FOND fontinfo data
belluzj Jan 11, 2018
91a2174
Fix problems with feaLib, TO REVERT ONCE IN UPSTREAM
belluzj Jan 22, 2018
9347544
Remove xfail on feature tests about includes and comments
belluzj Jan 22, 2018
c3e8f77
Fix open contours UFO -> .glyphs
belluzj Jan 25, 2018
5f984a2
Improve designspace generation and roundtrip
belluzj Jan 26, 2018
3824939
Handle master names like latest Glyphs (1114)
belluzj Feb 1, 2018
6b8da79
Require all UFOs to have the same family name
belluzj Feb 2, 2018
7f9e8e6
Cleanup the interpolation code a bit
belluzj Feb 2, 2018
663f3e3
Use the upstream feature parser with followIncludes
belluzj Feb 12, 2018
fe82a06
Fix empty fsType glyphs->ufo
belluzj Feb 13, 2018
8982196
Read instance data from the designspace
belluzj Feb 15, 2018
e5730bc
Bring bac `build_masters`, `apply_instance_data` etc
belluzj Feb 19, 2018
f3eae29
Add a test that calls build_masters
belluzj Feb 19, 2018
5c318ba
Fix some regressions from version 2.2.1
belluzj Feb 19, 2018
adf9155
Add example code
belluzj Feb 19, 2018
fa4433b
Fix rst formatting in README
belluzj Feb 19, 2018
d1e5dff
Don't crash if the UFO background is before the foreground
belluzj Feb 21, 2018
c63f8af
Fix crash when only a background
belluzj Feb 21, 2018
6f21462
Don't add a GDEF to the features when round-tripping
belluzj Feb 22, 2018
93e8a62
Depend on fontTools >= 3.24.0 and its designspaceLib
belluzj Feb 12, 2018
3a09bf7
Parse base64 encoded data in .glyphs
belluzj Mar 7, 2018
2034e9c
Handle in a basic way UFOs that have different feature files
belluzj Mar 7, 2018
6623d32
Warn if the UFO and designspace names don't match
belluzj Mar 8, 2018
e36097d
Keep custom styleMapStyleName from UFOs
belluzj Mar 8, 2018
1c19f25
Fix customName-related mistakes
belluzj Mar 8, 2018
5d61553
Fix roundtrip of custom master names and icon
belluzj Mar 14, 2018
fb5cbb9
Fix the fix of roundtrip of custom master name
belluzj Mar 14, 2018
c729de4
Update comments
belluzj Mar 19, 2018
cf79551
Parse unicode lists as written out by Glyphs 2.4.4
madig Mar 19, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ dist
# Unit test
.cache/
.tox/
.coverage
.coverage*
htmlcov

# Autosaved files
*~

# Additional test files
# (there's a script to download them from GitHub)
tests/noto-source*
# Files generated by tests
actual*
expected*
39 changes: 25 additions & 14 deletions Lib/glyphsLib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@
unicode_literals)

from io import open
import os
import logging

from fontTools.misc.py23 import tostr

from glyphsLib.builder import to_ufos
from glyphsLib.interpolation import interpolate, build_designspace
from glyphsLib.parser import load, loads
from glyphsLib.writer import dump, dumps
from glyphsLib.util import write_ufo

from glyphsLib.classes import __all__ as __all_classes__
from glyphsLib.classes import *
from glyphsLib.builder import to_ufos, to_designspace, to_glyphs
from glyphsLib.builder.instances import InstanceData
from glyphsLib.interpolation import interpolate
from glyphsLib.parser import load, loads
from glyphsLib.writer import dump, dumps
from glyphsLib.util import clean_ufo

__version__ = "2.2.2.dev0"

Expand Down Expand Up @@ -76,16 +77,26 @@ def build_masters(filename, master_dir, designspace_instance_dir=None,
paths from the designspace and respective data from the Glyphs source.
"""

ufos, instance_data = load_to_ufos(
filename, include_instances=True, family_name=family_name,
propagate_anchors=propagate_anchors)
font = GSFont(filename)
designspace = to_designspace(
font, family_name=family_name, propagate_anchors=propagate_anchors,
instance_dir=designspace_instance_dir)
ufos = []
for source in designspace.sources:
ufos.append(source.font)
ufo_path = os.path.join(master_dir, source.filename)
clean_ufo(ufo_path)
source.font.save(ufo_path)

if designspace_instance_dir is not None:
designspace_path, instance_data = build_designspace(
ufos, master_dir, designspace_instance_dir, instance_data)
return ufos, designspace_path, instance_data
designspace_path = os.path.join(master_dir, designspace.filename)
designspace.write(designspace_path)
# All the instance data should be in the designspace. That's why for
# now we return the full designspace in place of `instance_data`.
# However, other functions still expect the instance data to have
# a list of (path, something) tuples, hence the class `InstanceData`.
return ufos, designspace_path, InstanceData(designspace)
else:
for ufo in ufos:
write_ufo(ufo, master_dir)
return ufos


Expand Down
59 changes: 53 additions & 6 deletions Lib/glyphsLib/builder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@
from glyphsLib import classes
import defcon

# FIXME: (jany) import from fonttools
from glyphsLib.designSpaceDocument import DesignSpaceDocument

from .builders import UFOBuilder, GlyphsBuilder

logger = logging.getLogger(__name__)


def to_ufos(font, include_instances=False, family_name=None,
propagate_anchors=True, ufo_module=defcon):
def to_ufos(font,
include_instances=False,
family_name=None,
propagate_anchors=True,
ufo_module=defcon,
minimize_glyphs_diffs=False):
# TODO: (jany) Update documentation
"""Take .glyphs file data and load it into UFOs.

Takes in data as Glyphs.app-compatible classes, as documented at
Expand All @@ -38,7 +46,8 @@ def to_ufos(font, include_instances=False, family_name=None,
font,
ufo_module=ufo_module,
family_name=family_name,
propagate_anchors=propagate_anchors)
propagate_anchors=propagate_anchors,
minimize_glyphs_diffs=minimize_glyphs_diffs)

result = list(builder.masters)

Expand All @@ -47,13 +56,51 @@ def to_ufos(font, include_instances=False, family_name=None,
return result


def to_glyphs(ufos, designspace=None, glyphs_module=classes):
def to_designspace(font,
family_name=None,
instance_dir=None,
propagate_anchors=True,
ufo_module=defcon,
minimize_glyphs_diffs=False):
# TODO: (jany) Update documentation
"""Take .glyphs file data and load it into a Designspace Document + UFOS.

Takes in data as Glyphs.app-compatible classes, as documented at
https://docu.glyphsapp.com/

If include_instances is True, also returns the parsed instance data.

If family_name is provided, the master UFOs will be given this name and
only instances with this name will be returned.
"""
builder = UFOBuilder(
font,
ufo_module=ufo_module,
family_name=family_name,
instance_dir=instance_dir,
propagate_anchors=propagate_anchors,
use_designspace=True,
minimize_glyphs_diffs=minimize_glyphs_diffs)
return builder.designspace


def to_glyphs(ufos_or_designspace,
glyphs_module=classes,
minimize_ufo_diffs=False):
"""
Take a list of UFOs and combine them into a single .glyphs file.

This should be the inverse function of `to_ufos`,
so we should have to_glyphs(to_ufos(font)) == font
and also to_glyphs(to_designspace(font)) == font
"""
builder = GlyphsBuilder(
ufos, designspace=designspace, glyphs_module=glyphs_module)
# FIXME: (jany) duck-type instead of isinstance
if isinstance(ufos_or_designspace, DesignSpaceDocument):
builder = GlyphsBuilder(designspace=ufos_or_designspace,
glyphs_module=glyphs_module,
minimize_ufo_diffs=minimize_ufo_diffs)
else:
builder = GlyphsBuilder(ufos=ufos_or_designspace,
glyphs_module=glyphs_module,
minimize_ufo_diffs=minimize_ufo_diffs)
return builder.font
11 changes: 11 additions & 0 deletions Lib/glyphsLib/builder/anchors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

from fontTools.misc.transform import Transform

from glyphsLib.types import Point

__all__ = ['to_ufo_propagate_font_anchors']


Expand Down Expand Up @@ -104,3 +106,12 @@ def to_ufo_glyph_anchors(self, glyph, anchors):
x, y = anchor.position
anchor_dict = {'name': anchor.name, 'x': x, 'y': y}
glyph.appendAnchor(anchor_dict)


def to_glyphs_glyph_anchors(self, ufo_glyph, layer):
"""Add UFO glif anchors to a GSLayer."""
for ufo_anchor in ufo_glyph.anchors:
anchor = self.glyphs_module.GSAnchor()
anchor.name = ufo_anchor.name
anchor.position = Point(ufo_anchor.x, ufo_anchor.y)
layer.anchors.append(anchor)
59 changes: 59 additions & 0 deletions Lib/glyphsLib/builder/annotations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from __future__ import (print_function, division, absolute_import,
unicode_literals)

from .constants import GLYPHS_PREFIX
from glyphsLib.types import Point

LIB_KEY = GLYPHS_PREFIX + 'annotations'


def to_ufo_annotations(self, ufo_glyph, layer):
try:
value = layer.annotations
except KeyError:
return
annotations = []
for an in list(value.values()):
annot = {}
for attr in ['angle', 'position', 'text', 'type', 'width']:
val = getattr(an, attr, None)
if attr == 'position' and val:
val = list(val)
if val:
annot[attr] = val
annotations.append(annot)

if annotations:
ufo_glyph.lib[LIB_KEY] = annotations


def to_glyphs_annotations(self, ufo_glyph, layer):
if LIB_KEY not in ufo_glyph.lib:
return

for annot in ufo_glyph.lib[LIB_KEY]:
annotation = self.glyphs_module.GSAnnotation()
for attr in ['angle', 'position', 'text', 'type', 'width']:
if attr in annot and annot[attr]:
if attr == 'position':
position = Point()
position.x, position.y = annot[attr]
annotation.position = position
else:
setattr(annotation, attr, annot[attr])
layer.annotations.append(annotation)
Loading