Giter Site home page Giter Site logo

ufo2ft's Introduction

GitHub Actions status PyPI Version Codecov Join the chat at https://gitter.im/fonttools-dev/ufo2ft

ufo2ft

ufo2ft ("UFO to FontTools") is a fork of ufo2fdk whose goal is to generate OpenType font binaries from UFOs without the FDK dependency.

The library provides two functions, compileOTF and compileTTF, which work exactly the same way:

from defcon import Font
from ufo2ft import compileOTF
ufo = Font('MyFont-Regular.ufo')
otf = compileOTF(ufo)
otf.save('MyFont-Regular.otf')

In most cases, the behavior of ufo2ft should match that of ufo2fdk, whose documentation is retained below (and hopefully is still accurate).

Naming Data

As with any OpenType compiler, you have to set the font naming data to a particular standard for your naming to be set correctly. In ufo2fdk, you can get away with setting two naming attributes in your font.info object for simple fonts:

  • familyName: The name for your family. For example, "My Garamond".
  • styleName: The style name for this particular font. For example, "Display Light Italic"

ufo2fdk will create all of the other naming data based on thse two fields. If you want to use the fully automatic naming system, all of the other name attributes should be set to None in your font. However, if you want to override the automated system at any level, you can specify particular naming attributes and ufo2fdk will honor your settings. You don't have to set all of the attributes, just the ones you don't want to be automated. For example, in the family "My Garamond" you have eight weights. It would be nice to style map the italics to the romans for each weight. To do this, in the individual romans and italics, you need to set the style mapping data. This is done through the styleMapFamilyName and styleMapStyleName attributes. In each of your roman and italic pairs you would do this:

My Garamond-Light.ufo

  • familyName = "My Garamond"
  • styleName = "Light"
  • styleMapFamilyName = "My Garamond Display Light"
  • styleMapStyleName = "regular"

My Garamond-Light Italic.ufo

  • familyName = "My Garamond"
  • styleName = "Display Light Italic"
  • styleMapFamilyName = "My Garamond Display Light"
  • styleMapStyleName = "italic"

My Garamond-Book.ufo

  • familyName = "My Garamond"
  • styleName = "Book"
  • styleMapFamilyName = "My Garamond Display Book"
  • styleMapStyleName = "regular"

My Garamond-Book Italic.ufo

  • familyName = "My Garamond"
  • styleName = "Display Book Italic"
  • styleMapFamilyName = "My Garamond Display Book"
  • styleMapStyleName = "italic"

etc.

Additionally, if you have defined any naming data, or any data for that matter, in table definitions within your font's features that data will be honored.

Feature generation

If your font's features do not contain kerning/mark/mkmk features, ufo2ft will create them based on your font's kerning/anchor data.

In addition to Adobe OpenType feature files, ufo2ft also supports the MTI/Monotype format. For example, a GPOS table in this format would be stored within the UFO at data/com.github.googlei18n.ufo2ft.mtiFeatures/GPOS.mti.

Fallbacks

Most of the fallbacks have static values. To see what is set for these, look at fontInfoData.py in the source code.

In some cases, the fallback values are dynamically generated from other data in the info object. These are handled internally with functions.

Merging TTX

If the UFO data directory has a com.github.fonttools.ttx folder with TTX files ending with .ttx, these will be merged in the generated font. The index TTX (generated when using using ttx -s) is not required.

Color fonts

ufo2ft supports building COLR and CPAL tables.

If there is com.github.googlei18n.ufo2ft.colorPalettes key in font lib, and com.github.googlei18n.ufo2ft.colorLayerMapping key in the font or in any of the glyphs lib, then ufo2ft will build CPAL table from the color palettes, and COLR table from the color layers.

colorPalettes is a array of palettes, each palette is a array of colors and each color is a array of floats representing RGBA colors. For example:

<key>com.github.googlei18n.ufo2ft.colorPalettes</key>
<array>
  <array>
    <array>
      <real>0.26</real>
      <real>0.0</real>
      <real>0.23</real>
      <real>1.0</real>
    </array>
    <array>
      <real>0.86</real>
      <real>0.73</real>
      <real>0.28</real>
      <real>1.0</real>
    </array>
  </array>
</array>

colorLayerMapping is a array of color layers, each color layer is a array of layer name and palette color index. It is a per-glyph key, but if present in the font lib then it will be used for all glyphs that lack it. For example:

<key>com.github.googlei18n.ufo2ft.colorLayerMapping</key>
<array>
  <array>
    <string>color.1</string>
    <integer>1</integer>
  </array>
  <array>
    <string>color.2</string>
    <integer>0</integer>
  </array>
</array>

With these this key present, ufo2ft will copy the color layers into individual glyphs and setup COLR table.

Alternatively, if the color layers are already separate UFO glyphs, the com.github.googlei18n.ufo2ft.colorLayers font lib key can be used. It uses a table keyed by base glyph, and the value is an array of color layers, each color layer is an array of glyph name and palette color index. For example:

<key>com.github.googlei18n.ufo2ft.colorLayers</key>
<dict>
  <key>alef-ar</key>
  <array>
    <array>
      <string>alef-ar.color0</string>
      <integer>2</integer>
    </array>
  </array>
  <key>alefHamzaabove-ar</key>
  <array>
    <array>
      <string>alefHamzaabove-ar.color0</string>
      <integer>1</integer>
    </array>
    <array>
      <string>alefHamzaabove-ar.color1</string>
      <integer>2</integer>
    </array>
  </array>
<dict>

Setup Notes

If you are installing ufo2ft from source, note that the strict dependency versions in requirements.txt are for testing, see setup.py's install_requires and extras_requires for more relaxed dependency requirements.

ufo2ft's People

Contributors

adrientetar avatar anthrotype avatar athos-ribeiro avatar behdad avatar belluzj avatar benkiel avatar bkmgit avatar brawer avatar davelab6 avatar hoolean avatar ivanukhov avatar jamesgk avatar jenskutilek avatar justvanrossum avatar khaledhosny avatar kontur avatar lamby avatar m4rc1e avatar madig avatar marekjez86 avatar mashabow avatar medicalwei avatar moyogo avatar nsfmc avatar pyup-bot avatar simoncozens avatar twardoch avatar typemytype avatar typesupply avatar verbosus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ufo2ft's Issues

CFF charstring width is always encoded

This code:

    def getCharStringForGlyph(self, glyph, private, globalSubrs): 
        """ 
        Get a Type2CharString for the *glyph* 
 
        **This should not be called externally.** Subclasses 
        may override this method to handle the charstring creation 
        in a different way if desired. 
        """ 
        width = glyph.width 
        # subtract the nominal width 
        postscriptNominalWidthX = getAttrWithFallback(self.ufo.info, "postscriptNominalWidthX") 
        if postscriptNominalWidthX: 
            width = width - postscriptNominalWidthX 
        # round 
        width = round(width) 
        pen = T2CharStringPen(width, self.allGlyphs, 
                              roundTolerance=self.roundTolerance) 
        glyph.draw(pen) 
        charString = pen.getCharString(private, globalSubrs) 
        return charString 

If width is equal to postscriptDefaultWidthX, it does not have to be encoded. I suppose that value can itself be automatically set to be equal to whatever glyph width is most frequent.

Unicode Variation Selectors

I’m trying to convert and font that uses several Unicode Variation Selectors to UFO, but there is no support for them in either UFO or feature files. There is a proposal to support them in feature files but does not seem to be implemented.

Has any one managed to use VS with UFO work flow? Would it be better to add support for them in UFO (may be in lib somewhere?) and let ufo2ft compile it when building cmap or wait for the extended feature files syntax (this would mean feaLib would need to do the cmap table generation itself)?

Move or copy to googlei18n/ org

I was surprised that it wasn't there. Please either move, or just clone it there and make sure you push to both. There's some .git/config magic to do that. If you don't care about the location and don't want to be bothered by the magic and keeping the two in sync, then perhaps just move. Thanks!

importTTX can override sfntVersion

when the UFO data folder contains a *.ttx file, we use fonttools' TTFont.importXML to merge the table in the current TTFont that we are building.

However, if the ttFont element of the ttx file has a different sftntVersion than the TTFont instance we are importing into, the latter's sfntVersion attribute may be overwritten and we end up saving, for example, a CFF OpenType font with sfntVersion b"\x00\x01\x00\x00" instead of b"OTTO".

MarkAttachmentType and UseMarkFilteringSet?

There does not seem to be a way to set custom lookup flags to the generated feature, in particular I’ve an mkmk anchor that needs either MarkAttachmentType or UseMarkFilteringSet lookup flags to limits the feature to the set marks that have this anchor.

Adobe’s WriteFeaturesMarkFDK.py seems to almost always add MarkAttachmentType for mkmk features, but I’m not sure if this is right either.

May be we can (ab)use UFO groups to some how designate some group for lookup flag?

Use "ascender" attribute as fallback for similar info

optionally merge TTX tables found in UFO3 data folder

UFO3 has a 'data' folder where one could store extra, application specific data.

http://unifiedfontobject.org/versions/ufo3/data/

I propose that ufo2ft automatically merges into the compiled font any .ttx tables which it finds inside font.ufo/data folder, if the filename starts with the org.fonttools.* reverse domain.

Before I start working on the patch, I wanted to see if people liked the idea.

The immediate use case which I have in mind is merging the private TSI* tables where Microsoft Visual TrueType stores the hinting source data.

Having ufo2ft merge these automatically upon compilation would be handy I think.

What do you guys think?

ImportError: cannot import name OTFCompiler

Hmm, not sure why this doesn't work...

>>> import ufo2ft
>>> from robofab.world import OpenFont
>>> from ufo2ft import OTFCompiler
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name OTFCompiler
>>> 

Set width of glyphs with GDEF class 3 (mark) to zero?

I noticed that in fonts output by Glyphs, any glyph with GDEF class 3 has a width of zero. Should ufo2ft do the same? If so, we have to go back and change widths the compiled OTF/TTFs after the GDEF table has been compiled by feaLib.

Auto-generated kern feature could have wrong languagesystems

Does anyone understand why the current ufo2ft code runs a regexp over features.fea to find the language systems for the auto-generated features? The current logic seems a little surprising, and it might not work reliably.

  • The current logic assumes that there’s a manually entered feature file. That’s not guaranteed — a valid UFO may just kerning.plist but no features.fea.

  • Why should the languagesystems of some random GSUB or aalt feature determine the languagesystems for the kern feature?

  • The current regexp doesn’t actually retrieve the feature content in a reliable way. A feature file can include other feature files. Also, it doesn’t catch script statements.

Instead of the current logic, why doesn’t the code consider the Unicode codepoints being kerned? It would be tempting to just re-write this code, but I’d like to understand the rationale behind the current logic. Maybe there’s a reason for it?

LTR/RTL kernFeatureWriter

I'm not sure where to put this but I think it may be interesting for the current developments in #7 and #6 etc.

I extended the kernFeatureWriter of ufo2fdk/ufo3 branch for Jomhuria to support the creation of a fea-kerning file from ufo kerning.plist which works for LTR and RTL text.

Here: https://github.com/Tarobish/Jomhuria/blob/gh-pages/tools/getKernFeatureFromUFO.py

See this discussion unified-font-object/ufo-spec#16 where @behdad gave the hints how to approach this.

This is dependent on the ufo3k ufoLib.

If you're interested in this code we could look at how to integrate it. We should probably decide which is the best way to do RTL + LTR kerning from kerning.plist and subsequently discard some of the options from my code, to make it easier to use.

hmtx.lsb sometimes is off by one unit

I noticed that, in fonts generated by fontmake, sometimes the left sidebearing of some glyphs is smaller by one unit than what I should be, and by "should" I mean the xMin coordinate in the glyph.
When that happens, the bit 1 of the head table flags is turned off by fonttools, because not all glyphs in the font have the left sidebearings equal to the respective xMin.

The problem is that ufo2ft is using math.floor instead of round when setting the left sidebearing in the hmtx table:

a1ee5514

It turns out that, when removing overlaps with booleanOperations, coordinates may be converted from int to float even though they remain exactly as they were, well almost the same, e.g. they may go from 12 to 11.9999999999999. The loss of precision is probably due to the fact that they are scaled before being sent to pyclipper, and then the result is scaled again.

Now, when we give to math.floor such a value, that is going to return 11. But we know that the value was really a 12, and in fact the xMin coordinate in the glyf table for that glyph will be 12,

In TTF, coordinates are always rounded to integers, and we currently do that inside the fonttools ttGlyphPen.

In CFF, coordinates may be floats, though currently fontmake-generated fonts are always rounded. Fonttools added support for a round tolerance in t2CharStringPen, but support for this hasn't been added to ufo2ft and fontmake yet.

I think that if we want the lsb to always be the same as the xMin, we need to use the same round function that we use to round the coordinates.
Otherwise we end up with lsb which may not match the xMin values in the glyf table, and the head flag 1 being turned on/off in a seemingly random fashion.

Comments?

Should compileTTF() call cu2qu?

Right now I need to manually call cu2qu to convert fonts with cubic outlines before calling compileTTF(), but it might make some sense to do this by default in some way or another.

ufo2ft generates invalid output when glyph name starts in #

When a font contains glyphs whose names start with a #, e.g. #Qtail, ufo2ft should escape the # in its output. Currently, ufo2ft copies the string into its output without escaping, which leads to syntactically malformed feature files like this:

markClass _Qtail <anchor 183 79> @MC_#Qtail;

In feature file syntax, the # character starts a comment, so feaLib (and also any other feature files compiler) will choke on the output. See fonttools/fonttools#1100 and googlefonts/fontmake#347.

Group names hard coded in KernFeatureWriter, fails with @MMK_L_*-style group names.

Compare with the ufo2fdk KernFeatureWriter.getReferencedGroups() method, which looks at the actual group names being referenced from the kerning data.
I see there's some code for @MMK_L_*-style names, but it's not called. But it's not a good idea to do it that way: there should be no need to make assumptions about the group names.

FeatureWriter outputs illegal class names

e.g. I have a generated featurefile like this:

@MMK_R_FF000000000000020 = [A J];
public.kern2.@MMK_R_FF000000000000011 = [b h k l Thorn thorn];
  • In FEA, named glyph classes must start with @, which isn't currently enforced.
  • Also, class names must follow the same naming restrictions as glyph names (A-Z a-z 0-9 . (period) _ (underscore)), we let the user write correct data for the featurefile in the UFO but the FeatureWriter shouldn't output incorrect FEA code (UFO itself puts no name restrictions on groups names, except UFO3 which specificies kerning groups should begin with public.kernX)

(Lastly after the normalization pass we should make sure that no duplicate class names were produced, e.g. group and group# may yield the same name after normalization.)

Reproducible builds

I’m trying to make reproducible font builds with font make (i.e.rebuilding the same sources gives identical binaries). Useful for many things, but for me mainly to catch any regressions in the build machinery and source repository management.

I have so far been successful except in one small bit; the head.modified (and head.checkSumAdjustment, but I suspect it is secondary to the modified bit).

ufo2ft seems to always use the current date for this field which causes it to change for each build. Linux distributions seem to be converging on using an environment variable; SOURCE_DATE_EPOCH to override the current date for such builds. Ideally ufo2ft would check if it is set and use it and fall back to the current behavior otherwise. Alternatively, it can have an argument that would set the date.

WDYT?

fork ufo2fdk?

Currently ufo2ft shows up in github as "forked" from typesupply/ufo2fdk.
However, given the drastic changes to the api, I don't think the intention is to fold ufo2ft back in ufo2fdk repo.

If that is the case, then @jamesgk could delete the current ufo2ft repo, create a new Github repo called again "ufo2ft" and push his local copy to the new remote.

This way, Github will see it as an independent repository, instead of a fork of someone else's repo. The commit history will be kept intact however.

This would allow others to fork directly from James' "ufo2ft". At the moment, in fact, if one tries to fork from ufo2ft, Github will not allow it if the user has already forked ufo2fdk.

I had to resort to special "ufo2ft-*" branch names on my "hybrid" anthrotype/ufo2fdk fork, in order to be able to track both typesupply/ufo2fdk and jamesgk/ufo2ft...

name table records with same record id but different platform ids and contents

I'm raising this issue after fonttools/fontbakery#853

Since a goal is for fontmake output to match glyphsapp output when compiling .glyphs files, it seems like a needed feature request is to handle setting name records with the same record id but different platform ids and different contents.

Specifically I want ufo2ft to make nameID=4 ("Full Name") look the same as nameID=6 ("PostScript Name") when the platformID=3 ("Windows platform")

Default value for openTypeOS2Type

Currently if openTypeOS2Type is not set, it defaults to setting bit 2. I find this a bit surprising, shouldn’t not setting it be the same as setting it to an empty list i.e. no bits set?

autoUseMyMetrics is broken when convertCubics=True

in outlineCompiler, when convertCubics=True, we create copies of all the glyphs in order to convert their outlines with a cu2qu pen. However, we don't also copy their width attribute. Then later we compare the widths of the composite glyphs with their components to decide whether to USE_MY_METRICS, but by then all the widths are 0 (the default when width is missing) and hence the comparison 0 == 0 always holds true, and the flag is incorrectly set even when it should have not been set...

Note this does not affect fontmake, as the latter calls ufo2ft compiler with convertCubics=False (since it calls standalone cu2qu beforehand).

support "dist" feature for indic fonts in KernFeatureWriter

Some Noto fonts for Indic scripts don't have explicit MTI sources for the opentype features, but have instead self-contained *.glyphs sources with FEA code, and these rely on a Glyphs.app's feature that splits the kerning data at export time between a regular "kern" feature, and a "dist" feature only for kern pairs between Indic glyphs.

googlefonts/glyphsLib#223

Kerning on most Indic scripts is put into the dist feature on export... When exporting OTF/TTF from Glyphs the kerning is split so that LGC kerning is put in the kern feature and Indic kerning is put in the dist feature.
All kerning between glyphs that belong to Indic scripts is put into dist

Indic scripts expect "dist" because the latter is usually on by default, whereas kern isn't so.

I think ufo2ft's KernFeatureWriter should do this by default as well: i.e. emit not just "kern", but also "dist" for Indic glyphs, if any.

The argument that this would be a Glyphs.app-only feature may be true, but:

  1. this could be useful for any project, not just those that use Glyphs.app;
  2. the kern feature generation from kerning.plist is already happening inside ufo2ft, so it would be strange that dist feature was generated in glyphsLib while kern in ufo2ft.

Whether we extend the existing kern feature writer or add an additional dist feature writer subclass is not so important, as long as we agree this is needed here.

Georg said he has heuristic to determine what's Indic or not, probably by splitting ligatures at "_" and dropping "." suffixes. We could do a similar thing (I think we already do to determine whether kern pair is left-to-right or right-to-left).

Also, in *.glyphs source one can assign custom script property to a glyph (the default is given by the GlyphData.xml database used).

In UFO, there's isn't such thing. So I was thinking of defining a private UFO glyph lib entry that specifies a custom script (as well one for category, which could be useful for other things) for glyphs that either don't have a unicode assigned, or they do have one but the user may want (for whatever reason) to override the default script value for them.

Comments?

TTF generation fails if font does not have .notdef glyph

I'm using this working patch for now:

diff --git a/Lib/ufo2ft/outlineOTF.py b/Lib/ufo2ft/outlineOTF.py
index c921cc3..2abae71 100644
--- a/Lib/ufo2ft/outlineOTF.py
+++ b/Lib/ufo2ft/outlineOTF.py
@@ -811,6 +811,9 @@ class OutlineTTFCompiler(OutlineCompiler):
             self.allGlyphs[name].draw(pen)
             glyf[name] = pen.glyph()

+        pen = TTGlyphPen(self.allGlyphs)
+        glyf['.notdef'] = pen.glyph()
+

 class StubGlyph(object):

Not rounding coordinates in CFF

See:
http://blog.typekit.com/2015/10/01/smoother-curves-with-decimal-coordinate-values/

The gist of it is, non-integer numbers are allowed in CFF, and they seem to work. Given that UPEM 1000 is used in CFF, and we are interpolating a lot, we should consider using those sometimes. Now, encoding a non-integer takes 5 bytes (instead of 1 or 2 for most numbers), so we should be very cautious about this. But would be good to think about supporting it (and in fonttools's t2CharStringPen).

Since coordinate data is encoded using relative coordinates (essentially 2d vectors), a good heuristic would be, to compare the rounding error to the magnitude of the vector, or to the individual components (x/y), or possibly even the change in direction. So, perhaps adding a tolerance would be enough, but we have to consider different cases, test with a bunch of fonts, and decide what rule is most useful.

On the fonttools side, we need to support these three cases:

  • Round everything,
  • Round nothing,
  • Round some things,

again, using a tolerance does all of them. Value of 0 means don't round anything (no rounding error is tolerated). Value of 1 means round everything (100% rounding error is tolerated!). Values like 0.05 might be good for most workflows, specially for interpolations.

@readroberts can you share your script font with us for testing please?

Corrected group names are not propagated

KernFeatureWriter crashes here because while leftClasses has corrected group names, self.classPairKerning still has the original names.

Traceback (most recent call last):
  File "C:\Users\Admin\Downloads\trufont\Lib\defconQt\fontView.py", line 988, in exportFile
    otf = self.font.getRepresentation("defconQt.TTFont")
  File "C:\Python34\lib\site-packages\defcon\objects\base.py", line 337, in getRepresentation
    representation = factory["factory"](self, **kwargs)
  File "C:\Users\Admin\Downloads\trufont\Lib\defconQt\representationFactories\openTypeFactory.py", line 5, in TTFontFactory
    otf = compileOTF(font)
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\__init__.py", line 29, in compileOTF
    featureCompilerClass, kernWriter, markWriter)
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\__init__.py", line 18, in _compile
    featureCompiler.compile()
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\makeotfParts.py", line 26, in compile
    self.setupFile_features()
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\makeotfParts.py", line 59, in setupFile_features
    autoFeatures["kern"] = self.writeFeatures_kern()
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\makeotfParts.py", line 83, in writeFeatures_kern
    return writer.write()
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\kernFeatureWriter.py", line 57, in write
    self._removeConflictingKerningRules()
  File "C:\Python34\lib\site-packages\ufo2ft-0.1-py3.4.egg\ufo2ft\kernFeatureWriter.py", line 193, in _removeConflictingKerningRules
    lGlyphs = leftClasses[lClass]
KeyError: 'public.kern1.@MMK_L_FF000000000000023'

Content of leftClasses:

dict_keys(['@public.kern1.MMK_L_FF000000000000022', '@public.kern1.MMK_L_FF000000000000002', '@public.kern1.MMK_L_FF000000000000020', '@public.kern1.MMK_L_FF000000000000009', '@public.kern1.MMK_L_FF000000000000013', '@public.kern1.MMK_L_FF000000000000014', '@public.kern1.MMK_L_FF000000000000011', '@public.kern1.MMK_L_FF000000000000010', '@public.kern1.MMK_L_FF000000000000017', '@public.kern1.MMK_L_FF000000000000023', '@public.kern1.MMK_L_FF000000000000019', '@public.kern1.MMK_L_FF000000000000018', '@public.kern1.MMK_L_FF000000000000005', '@public.kern1.MMK_L_FF000000000000021', '@public.kern1.MMK_L_FF000000000000016', '@public.kern1.MMK_L_FF000000000000006', '@public.kern1.MMK_L_FF000000000000004', '@public.kern1.MMK_L_FF000000000000003', '@public.kern1.MMK_L_FF000000000000015', '@public.kern1.MMK_L_FF000000000000012', '@public.kern1.MMK_L_FF000000000000008', '@public.kern1.MMK_L_FF000000000000007'])

Cast unitsPerEm to int?

I'm getting an error while compiling a ufo made with DesignSpaceProcessor:

Python 3.6.1 (default, Jul 19 2017, 13:24:40)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from designSpaceDocument.ufoProcessor import DesignSpaceProcessor
>>> processor = DesignSpaceProcessor(ufoVersion=3)
>>> processor.read('test.designspace')
>>> processor.loadFonts()
>>> ufo = processor.makeInstance(processor.instances[0])
>>> from ufo2ft import compileOTF
>>> otf = compileOTF(ufo)
Underline thickness not set in UFO, defaulting to UPM * 0.05
Underline position not set in UFO, defaulting to UPM * -0.075
Underline thickness not set in UFO, defaulting to UPM * 0.05
Underline position not set in UFO, defaulting to UPM * -0.075
Underline thickness not set in UFO, defaulting to UPM * 0.05
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/ufo2ft/__init__.py", line 44, in compileOTF
    postProcessor = PostProcessor(otf, ufo)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/ufo2ft/postProcessor.py", line 15, in __init__
    otf.save(stream)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/fontTools/ttLib/__init__.py", line 219, in save
    self._writeTable(tag, writer, done)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/fontTools/ttLib/__init__.py", line 658, in _writeTable
    tabledata = self.getTableData(tag)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/fontTools/ttLib/__init__.py", line 669, in getTableData
    return self.tables[tag].compile(self)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/fontTools/ttLib/tables/_h_e_a_d.py", line 64, in compile
    data = sstruct.pack(headFormat, self)
  File "/Users/mnakamura/.pyenv/versions/3.6.1/lib/python3.6/site-packages/fontTools/misc/sstruct.py", line 75, in pack
    data = struct.pack(*(formatstring,) + tuple(elements))
struct.error: required argument is not an integer

This error seems to be caused by ufo.info.unitsPerEm; fonttools expects an int but it is a float actually.

>>> type(ufo.info.unitsPerEm)
<class 'float'>
>>> ufo.info.unitsPerEm
1000.0

Try to determine OS/2 fsSelection bit 8? (WWS compliance)

Right now, ufo2ft only tries to determine bits 0, 5, and 6:
https://github.com/googlei18n/ufo2ft/blob/6184b1493bc4afc6969bd2516d02f3f616cb5484/Lib/ufo2ft/outlineOTF.py#L512

But it seems Glyphs also will set bit 8 when deemed appropriate. Quick reference for these bits:
https://www.microsoft.com/typography/otspec/os2.htm#fss

Should ufo2ft also try to determine whether this bit should be set? Seems somewhat complicated but maybe it's what people would expect.

Emit table GDEF with LigatureCaretByPos statements

Could ufo2ft generate feature files with table GDEF blocks, and LigatureCaretByPos statements for ligatures?

For example, when exporting Noto Sans Hebrew as an OpenType font, Glyphs.app generates a feature file with the following table GDEF block. It would be great if ufo2ft could emit something equivalent, so that the final fonts contain a GDEF table that also contains info about ligatures.

table GDEF {
 GlyphClassDef [alef-hb bet-hb gimel-hb dalet-hb he-hb vav-hb zayin-hb het-hb t\
et-hb yod-hb finalkaf-hb kaf-hb lamed-hb finalmem-hb mem-hb finalnun-hb nun-hb \
samekh-hb ayin-hb finalpe-hb pe-hb finaltsadi-hb tsadi-hb qof-hb resh-hb shin-h\
b tav-hb yodhiriq-hb yodyodpatah-hb ayinaltone-hb shinshindot-hb shinsindot-hb \
shindageshshindot-hb shindageshsindot-hb alefpatah-hb alefqamats-hb alefdagesh-\
hb betdagesh-hb gimeldagesh-hb daletdagesh-hb hedagesh-hb vavdagesh-hb zayindag\
esh-hb tetdagesh-hb yoddagesh-hb finalkafdagesh-hb kafdagesh-hb lameddagesh-hb \
memdagesh-hb nundagesh-hb samekhdagesh-hb finalpedagesh-hb pedagesh-hb tsadidag\
esh-hb qofdagesh-hb reshdagesh-hb shindagesh-hb tavdagesh-hb vavholam-hb betraf\
e-hb kafrafe-hb perafe-hb],# Base
 , # Liga
 [etnahtaleft-hb segolta-hb shalshelet-hb zaqefqatan-hb zaqefgadol-hb tipehalef\
t-hb reviamugrash-hb zarqa-hb pashta-hb yetiv-hb tevirleft-hb gereshaccent-hb g\
ereshmuqdam-hb gershayimaccent-hb qarneypara-hb telishagedola-hb pazer-hb atnah\
hafukh-hb munahleft-hb mahapakhleft-hb merkhaleft-hb merkhakefulaleft-hb dargal\
eft-hb qadma-hb telishaqetana-hb yerahbenyomoleft-hb ole-hb iluy-hb dehi-hb zin\
or-hb masoracircle-hb sheva-hb hatafsegol-hb hatafsegol_zerowidthjoiner_siluqle\
ft-hb hatafpatah-hb hatafpatah_zerowidthjoiner_siluqleft-hb hatafqamats-hb hata\
fqamats_zerowidthjoiner_siluqleft-hb hiriq-hb tsere-hb segol-hb patah-hb qamats\
-hb holam-hb holamhaser-hb qubuts-hb dagesh-hb siluqleft-hb rafe-hb shindot-hb \
sindot-hb upperdot-hb lowerdot-hb qamatsqatan-hb judeospanishvarika-hb], # Mark\

 ;
 LigatureCaretByPos vavvav-hb 221;
LigatureCaretByPos vavyod-hb 206;
LigatureCaretByPos yodyod-hb 191;
LigatureCaretByPos aleflamed-hb 242;
} GDEF;

Adding Filter module

This is a follow up thread of googlefonts/fontmake#275

Overview
Create ufo2ft/filter.py module, which is constructed by the private com.github.googlei18n.ufo2ft.filters key in ufo.lib

Some pseudocode

class Filter:
  def __init__(self, ufo):
    if not ufo['com.github.googlei18n.ufo2ft.filters']:
      return
    self.transform = ...
    self.keepoverlap = ...
  def apply(ufo):
    '''Apply the filter to ufo'''
    for glyph in ufo:
        glyph.move(self.transform)
        ....

I was thinking of the following suggestions from Cosimo:

The default filters would live in a sub-package, e.g. ufo2ft.filters, each in its own module. They could be based on the PointPen API (see ufoLib/pointPen.py), which is the standard way in the UFO world to manipulate outlines. They would work like "filter" pens, i.e. pens that take another pen that actually does the drawing, and before passing drawing commands to the inner pen, they do some transformations (the fonttools TransformPen is an example).

It's a great idea to make filter as a intercepter (Alternatively we will use glyph.move() provided by defcon to do the transformation, but it's less versatile than pen I guess).

From my understanding it looks like this:

# filterPen.py
class FilterPen:
  def __init__(self, ufo, pen):
    self.transform = XXXX
    self.pen = pen
  def _moveTo(self, pt):
    pt += transform
    self.pen._moveTo(pt)
  def _curveTo(self, *pts):
    for pt in *pts:
      pt += transform
    self.pen._curveTo(*pts) 

# outlineCompiler.py
def setupTable_glyf(self):
  ...
  pen = TTGlyphPen(allGlyphs)
  filterpen = FilterPen(ufo, pen)
  glyph.draw(filterpen)

def getCharStringForGlyphs(self, glyph, ..):
  pen = T2CharString...
  filterpen = FilterPen(ufo, pen)
  glyph.draw(filterpen)

Please correct me if I'm wrong, since I don't know how to use the pointPen.py as a base class. And this approach seems to work as well.

Add hooks for pre- and post-processing

Working on the Ubuntu font with its' special requirements made me think about pre-/post-processing hooks for fontmake or ufo2ft. The goal is to write custom code that takes care of things like reading in the maxp table data present in the UFO or adding a legacy kerning table to the compiled TTF, all without compromising fontmake's simplicity.

(bold) and (bold) should match. Don't they match already?

not certain how to interpret this new warning in the pipeline
WARNING:fontTools.ttLib.tables.O_S_2f_2:fsSelection bit 5 (bold) and head table macStyle bit 0 (bold) should match

while building src/NotoSansArabicUI-MM.glyphs (possibly others)

handle composite decomposition and overlap removal

To properly support Glyphs.app's Filter as well as Pre-Filter (#120), ufo2ft needs to take care of performing decomposition of composite glyphs and the overlap removal, which is currently done in fontmake, before the ufo2ft compiler is run.
We need to move that logic in here so we can apply the pre-filters before the decomposition and overlap removal steps.

Cf. notofonts/noto-source#84 (comment)

use new `public.postscriptNames` lib key

This was recently introduced in the UFO spec:

unified-font-object/ufo-spec@c8620ff

It's a global mapping stored in the font's lib.plist, and not a GLIF's lib property as we initially implemented it in ufo2ft and glyphsLib:

https://github.com/googlei18n/ufo2ft/blob/13e5ab68ffa683e2776263ef868d57781d91be9b/Lib/ufo2ft/otfPostProcessor.py#L49
https://github.com/googlei18n/glyphsLib/blob/9387810ea3c540bb4d0412282e8a83c9e8b6bc21/Lib/glyphsLib/builder.py#L618

So we need to fix both.

Also, this is API break, so it would warrant a major version bump -- but ufo2ft have no formal API, nor versions.

support "abvm" and "blwm" in MarkFeatureWriter

we should extend the MarkFeatureWriter (or add new writer sublcass) so that we write these Indic-related features.

The code to create mark and abvm/blwm is very similar.
First split all glyphs by Indic script and all other. For the first group, put all anchors with a name in (‘top’, ‘topleft’, ‘topright’, ‘candra’, ‘bindu’, ‘candrabindu’) into abvm and all (‘bottom’, ‘nukta’, ‘bottomleft’, ‘bottomright’) in blwm. All others are checked if they are in the top or bottom part of he letter.

googlefonts/glyphsLib#223 (comment)

related to #176

PyPI?

Can we have ufo2ft published on PyPI?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.