Coder Social home page Coder Social logo

fontmath's People

Contributors

adrientetar avatar anthrotype avatar behdad avatar benkiel avatar dependabot[bot] avatar justvanrossum avatar khaledhosny avatar letterror avatar madig avatar miguelsousa avatar moyogo avatar pyup-bot avatar schriftgestalt avatar simoncozens avatar typemytype avatar typesupply 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fontmath's Issues

No module named mathFunctions

I get this mathFunctions module error when trying to use MutatorMath.

File "/usr/local/lib/python2.7/dist-packages/mutatorMath/ufo/instance.py", line 8, in <module> from fontMath.mathKerning import MathKerning File "/usr/local/lib/python2.7/dist-packages/fontMath/mathKerning.py", line 3, in <module> from mathFunctions import add, sub, mul, div ImportError: No module named mathFunctions

I could correct this issue by changing the import statement inmathKerning.py and mathInfo.py in to:
from fontMath.mathFunctions import add, sub, mul, div
I tried this Ubuntu 32 bit with Python 2.7

mathGlyph.py doctest failing

This test is failing. The result is,

('curve', (0, 50), False, 'name 1', 'point 1'),
(None, (0, 75), False, None, None),
(None, (25, 100), False, None, None),
(None, (25, 100), False, None, None),  <--- line 4
(None, (50, 100), False, None, None),  <--- line 5
('curve', (50, 100), True, 'name 2', 'point 2'),
(None, (75, 100), False, None, None),
(None, (100, 75), False, None, None),
('curve', (100, 50), True, 'name 3', 'point 3'),
(None, (100, 25), False, None, None),
(None, (75, 0), False, None, None),
('curve', (50, 0), False, 'name 4', 'point 4'),
(None, (25, 0), False, None, None),
(None, (0, 25), False, None, None)

Lines 4 and 5 are what's different from the expected result.
I tried with both RoboFab's master and ufo3k branches. The outcome was the same.

Can someone else confirm this?

FilterRedundantPointPen and start points

I came across a situation where depending on the start point, FilterRedundantPointPen is not able to catch redundant offcurve points.

In a glyph like the one here, the offcurve points stay in place after running the pen.

<?xml version='1.0' encoding='UTF-8'?>
<glyph name="C" format="2">
  <advance width="500"/>
  <outline>
    <contour>
      <point x="298" y="132"/>
      <point x="298" y="80"/>
      <point x="298" y="80" type="curve"/>
      <point x="600" y="80" type="line"/>
      <point x="600" y="132" type="line"/>
      <point x="298" y="132" type="line"/>
    </contour>
  </outline>
</glyph>

In the case below, FilterRedundantPointPen works as expected by getting rid of the 2 points without a type.

<?xml version='1.0' encoding='UTF-8'?>
<glyph name="C" format="2">
  <advance width="500"/>
  <outline>
    <contour>
      <point x="298" y="80" type="curve"/>
      <point x="600" y="80" type="line"/>
      <point x="600" y="132" type="line"/>
      <point x="298" y="132" type="line"/>
      <point x="298" y="132"/>
      <point x="298" y="80"/>
    </contour>
  </outline>
</glyph>

Don't allow conflicting kerning to escape MathKerning.

During the kerning extraction process, loop through the kerning and catch any conflicting pairs. Either toss or average the pairs to eliminate the conflict. This is not a 100% correct solution to the problem, but there is no way to algorithmically resolve this problem. However, sending out conflicting pairs is going to result in data that is 100% in conflict, so we need to do something about it.

[mathTransform] what's the purpose of `test_functions` unit test?

It's not clear to me what the purpose of test_mathTransform.py::MathTransformTest.test_functions is.

It seems to assert that at least for some of the _testData, the three testFunctions yield slightly different results.

However:

  • only the results of the first and second functions are compared, the third seems to be ignored;
  • the assertion is too broad and catch-all: it's not very useful to know that sometimes given some random interpolation values results may be different. I would like to know when, how different and why.

Another problem is that since the interpolation value is random.random(), sometimes the test can unpredictably fail (i.e. FontMathWarning is never raised, all results are same between functions), for example:

https://travis-ci.org/typesupply/fontMath/jobs/172252357#L356

I think we need to narrow this test down a little bit, though I'm not sure how.

Maybe @typesupply or @moyogo can shed some light?

def test_functions(self):
        """
        In this test various complex transformations are interpolated using
        3 different methods:
          - straight linear interpolation, the way glyphMath does it now.
          - using the MathTransform interpolation method.
          - using the ShallowTransform with an initial decompose and final
            compose.
        """
        value = random()
        testFunctions = [
            _polarDecomposeInterpolationTransformation,
            _mathPolarDecomposeInterpolationTransformation,
            _linearInterpolationTransformMatrix,
        ]
        with self.assertRaisesRegex(
                FontMathWarning,
                "Minor differences occured when "
                "comparing the interpolation functions."):
            for i, m in enumerate(_testData):
                m1, m2 = m
                results = []
                for func in testFunctions:
                    r = func(m1, m2, value)
                    results.append(r)
                if not results[0] == results[1]:
                    raise FontMathWarning(
                        "Minor differences occured when "
                        "comparing the interpolation functions.")

Improvement of MathInfo results with incomplete data.

This is an interesting problem with mathInfo objects when processing attributes that do not exist in the other object. This can happen when one of the masters has more values set than the other. For instance when preparing the "deltas", the objects with relative data

Bottom line is: when c = a - b, then also a = b + c, Currently this is not the case.

This is a proposed fix: https://github.com/typesupply/fontMath/tree/fix-mathinfo

This is a test. Best to see with and without the proposed fix.

from fontParts.world import RFont
from fontMath import MathInfo
import fontMath
print(fontMath.__file__)

# master 1
f1 = RFont()
f1.info.ascender = 800				# present in both masters
f1.info.descender = -200			# present in both masters
f1.info.openTypeHheaAscender = 500	# example value that won't be in master 2

m1 = f1.info.toMathInfo()

f2 = RFont()
f2.info.ascender = 750				# present in both masters
f2.info.descender = -180			# present in both masters
f2.info.openTypeOS2TypoAscender = 300	# example value that won't be in master 1

m2 = f2.info.toMathInfo()

# subtract m2 from m1
m3 = m1 - m2

# extract to new font
f3 = RFont()
f3.info.fromMathInfo(m3)
print("check:", f3.info.ascender)
# this is 800 - 750 = 50
assert f3.info.ascender == 50	# check

print("check:", f3.info.descender)
# this is -200 - -180 = -20
assert f3.info.descender == -20	# check

# here we have wrong results
print("unexpected:", f3.info.openTypeHheaAscender)
print("unexpected:", f3.info.openTypeOS2TypoAscender)

# if     c = a - b
# then   a = c + b

m4 = m3 + m2
f4 = RFont()
f4.info.fromMathInfo(m4)
print("openTypeHheaAscender m4:", f4.info.openTypeHheaAscender, f1.info.openTypeHheaAscender)
print("openTypeOS2TypoAscender m4:", f4.info.openTypeOS2TypoAscender, f1.info.openTypeOS2TypoAscender)


# when a value is not present in the other master
# the delta should be 0, no change, 

# maybe it should be like this:
# <value a> - <unknown b> = 0
# <value a> + <unknown b> = <value a>

# <unknown a> - <value b> = 0
# <unknown a> + <value b> = <value a>

# scalar * <unknown b> = <unknown b>
# <unknown b> / factor = <unknown b>

# This works in mutatormath as it started with the actual default object
# but varlib starts with the esult of 1.0 * default object.
# 

MathGlyph: Variable fonts loose carefully prepared stacked nodes

Hi fontMath team. I am having trouble with a variable font project that uses stacked nodes to keep compatibility across masters. Tracing the root of the problem I have arrived here. I've also heard colleagues complaining about facing similar issues with their projects. Fiddling with the code I think I have found a civilized solution and I am offering it to you.

Fix utilizes simple name/tag technique to sort out the newly introduced nodes from MathGlyphPen, thus leaving stacked nodes intentionally made by the type designer alone.

Problem first referred here: LettError/ufoProcessor#35
I believe my issue is similar to: #127
Please see the attached code: mathGlyph.zip

missing README file

Does anybody fancy adding a short README text file at the top-level of the repository?

I would like to use that for the long_description in setup.py, so that it can also be used for the project homepage on PyPI.

If it is formatted in reStructuredText instead of markdown it'd be even better, as currently PyPI cannot render .md files while Github can render .rst ones just fine.

It's easy to convert md to rst, e.g. with pandoc:
pandoc --from=markdown --to=rst --output=README.rst README.md

MathInfo: subtracting list and None attributes gives invalid results

Say you have two Info objects, a and b; in a, the postscriptFamilyBlues is some list of integers, whereas in b object, that attribute is None (not an empty list).
When subtracting a - b, the resulting object will have the attribute set to 0, because of this code here:

elif a is not None and b is None:
#v = a
if func == add:
v = a
else:
v = 0
elif b is not None and a is None:
#v = b
if func is add:
v = b
else:
v = 0

but that's invalid, because the type of postscriptFamilyBlues attribute must be an Optional[list], not int.

I don't understand the rationale of special-casing a subtrahend value of None. For the "add" function it simply sets the value to self (i.e. adding None doesn't do anything). Why for subtraction it would be any different?

mathKerning is wrong in many ways

All in _processMathOne(). Two major issues I see:

  • If a pair is not available in one of the sets, it assumes 0, whereas it should instead use the effective kerning value for that pair, which might come from a glyph-class, class-glyph, or class-class. This one is not too hard to fix.
  • If the two sides have different groups, it arbitrarily merges them. Instead, we should classify glyphs into new groups and translate kerns over. I started https://github.com/behdad/fonttools/blob/master/Lib/fontTools/misc/classifyTools.py for that purpose, though I want to extend it to support named sets.

Rounding is done using fontTools.misc.py23.round3 instead of fontTools.misc.fixedTools.otRound

This is problematic, as varLib uses otRound, so static instances do not exactly match their cousins inside a variable font made with varLib. In testing this with Cantarell, I found a large number of off-by-ones between the two rounding methods.

Simply swapping the methods out doesn't work, as round3() takes an ndigits argument, while otRound doesn't. Maybe as a compromise, round3() can be used when there is an ndigits argument, otherwise otRound? Can provide PR.

Edit: although, varLib is not the only possible user. I haven't looked at mutatorMath.

MathGlyph may need __lt__ and __eq__ for Python 3 support

Right now the mutatorMath InstanceWriter cannot properly generate glyphs on Python 3 because MathGlyph is missing the required __lt__ and __eq__ methods (see also LettError/MutatorMath#65 for a similar issue). Here we have the current __cmp__:

https://github.com/typesupply/fontMath/blob/8988b88531a8613a2716c34643327214ff710338/Lib/fontMath/mathGlyph.py#L100

I patched my local copy of mathGlyph.py with a simple:

    def __eq__(self, other):
        self.__cmp__(other)

    def __lt__(self, other):
        self.__cmp__(other)

This all works fine, and mutatorMath is happy. I wonder what the right behavior for a “proper” __lt__ would be, though, if any.

guideline api

there is a difference between fontParts and defcon
in defcon a guideline is actually a dict and fontMath iterates over all the keywords

This is not possible in fontParts...

g = CurrentGlyph()

for key in g.naked().guidelines[0]:
    print(key)
for key in g.guidelines[0]:
    print(key)
x
y
angle
identifier
Traceback (most recent call last):
  File "<untitled>", line 5, in <module>
TypeError: 'RGuideline' object is not iterable

MathKerning loses groups data when multiplied

_processMathTwo() does not copy the data of MathKerning.groups which leads to wrong assumptions in cleanup and guessPairType, which can result in exceptions getting lost.

A small test is here:

from fontMath.mathKerning import MathKerning
from defcon.objects.font import Font

f = Font()
f.groups["public.kern1.groupA"] = ['one', 'Bee']
f.groups["public.kern2.groupB"] = ['two', 'Three']
f.kerning[('public.kern1.groupA', 'public.kern2.groupB')] = -100
m = MathKerning(f.kerning, f.groups)

print(m.groups())
print((m*1.0).groups())

>>> {'public.kern1.groupA': ['one', 'Bee'], 'public.kern2.groupB': ['two', 'Three']}
>>> {}

A bigger test with related issue is here.

scaling a font's UPEM with fontMath

I would like to scale a UFO's unitsPerEm, while keeping the font the same by scaling everything else at the same time.
I thought I could simply use fontMath since it already implements __mul__ on info, kerning and glyph objects.
Here's what I have:

https://gist.github.com/anthrotype/62d0bfe1d38b8f11a199bd3b66574bcc

Now the problem is the components' xScale and yScale are also scaled by the given factor, which is not what I was expecting. Say they are set to 1.0 in the input font, if I multiply the glyphs by a factor or 2, I get the component scale set to 2.0. The simple contour glyphs have also been scaled by the same amount already, I don't want the components to be scaled again.

I was thinking we may add an option in MathGlyph constructor to only scale the component's offsets and exclude the other scale/shear attributes?

Update needed for interaction with fontParts objects

MathGlyph objects (and maybe others) need to test if the object is from defcon or fontParts.

As an example, creating a new MathGlyph from a fontParts glyph fails here:
https://github.com/typesupply/fontMath/blob/master/Lib/fontMath/mathGlyph.py#L715

Here's a test:

from fontMath.mathGlyph import _expandImage
from fontParts.nonelab import RFont

f = RFont()
f.newGlyph("A")
g = f["A"]
print type(g.image)
try:
	print _expandImage(g.image)
except TypeError:
	print "meh1"

from defcon.objects.font import Font as DFont
f = DFont()
f.newGlyph("A")
g = f["A"]
print type(g.image)
try:
	print _expandImage(g.image)
except TypeError:
	print "meh2"
<class 'fontParts.nonelab.image.RImage'>
meh1
<class 'defcon.objects.image.Image'>
{'color': None, 'transformation': (1, 0, 0, 1, 0, 0), 'fileName': None}

MathGlyphTest.test_guidelines_mul failing on Alpine Linux

Hello,

I'm currently packaging fontMath for Alpine Linux and the mentioned tests fails. Here's the output:

___________________________________________________________________________________________________ MathGlyphTest.test_guidelines_mul ___________________________________________________________________________________________________

self = <fontMath.test.test_mathGlyph.MathGlyphTest testMethod=test_guidelines_mul>

    def test_guidelines_mul(self):
        glyph1 = self._setupTestGlyph()
        glyph1.guidelines = [
            dict(x=1, y=3, angle=5, name="test", identifier="1",
                 color="0,0,0,0")
        ]
        glyph2 = glyph1 * 3
        expected = [
            dict(x=1 * 3, y=3 * 3, angle=5, name="test", identifier="1",
                 color="0,0,0,0")
        ]
>       self.assertEqual(glyph2.guidelines, expected)
E       AssertionError: Lists differ: [{'x'[17 chars]le': 4.999999999999999, 'name': 'test', 'ident[28 chars],0'}] != [{'x'[17 chars]le': 5, 'name': 'test', 'identifier': '1', 'color': '0,0,0,0'}]
E       
E       First differing element 0:
E       {'x':[16 chars]le': 4.999999999999999, 'name': 'test', 'ident[27 chars]0,0'}
E       {'x':[16 chars]le': 5, 'name': 'test', 'identifier': '1', 'color': '0,0,0,0'}
E       
E       - [{'angle': 4.999999999999999,
E       + [{'angle': 5,
E           'color': '0,0,0,0',
E           'identifier': '1',
E           'name': 'test',
E           'x': 3,
E           'y': 9}]

Lib/fontMath/test/test_mathGlyph.py:398: AssertionError

We're using Python 3.8.1

Anisotropic interpolation produces wrong (-90°) Italic angle for instances

I filed this issue in the wrong repo:
LettError/MutatorMath#259

Copy-pasting the original issue below.
Please follow the link above for some thoughts by @LettError.

First pointed out by @kaibernau:

An anisotropic interpolation will result in an unexpected Italic angle for the instance UFOs.
Anisotropic interpolation basically splits the x- and y- axis by allowing different factors for each.
This is how to indicate it for a given instance:

        <dimension name="weight" xvalue="57" yvalue="52"/>

In the attached project, the Italic angle for both masters is -11°.
Using anisotropic interpolation, the italic angle for the instance ends up as -90°.
This is true for any value of y, including 0 and = x

I reproduced Kai’s finding using the AFDKO’s makeinstancesufo:

makeinstancesufo -ac -d designspace.designspace
# -ac switches off autohint/checkoutlinesufo

italic_angle_issue.zip

factorAngle changes break makeinstancesufo tests

Hi there,
We noticed the fontMath 0.8.1 update breaks some of our tests in the AFDKO, specifically in our makeinstancesufo tool. It seems to be tied to these changes in factorAngle. The new italicAngle values after this update are concerning to us; we're curious what the purpose of this change was.

Here's an example:
files here:
input.zip

makeinstancesufo -d font.designspace -i 5 -n
Running that will produce a bold.ufo instance
The italicAngle value here was previously 2, now it's outputting 1.4430379746835442:

     <key>italicAngle</key>
-    <integer>2</integer>
+    <real>1.4430379746835442</real>
     <key>openTypeHheaAscender</key> 

italicAngle value changes within our other tests were all similar:

    <key>italicAngle</key>
-   <integer>2</integer>
+   <real>0.082278481</real>
    <key>openTypeHheaAscender</key>
    <key>italicAngle</key>
-   <integer>2</integer>
+   <real>0.7341772152</real>
    <key>openTypeHheaAscender</key>
     <key>italicAngle</key>
-    <integer>2</integer>
+    <integer>0</integer>
     <key>openTypeHheaAscender</key>
    <key>italicAngle</key>
-   <integer>-180</integer>
+   <integer>0</integer>
    <key>postscriptBlueFuzz</key>

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.