GithubHelp home page GithubHelp logo

compositor's People

Contributors

adrientetar avatar benkiel avatar gferreira avatar jenskutilek avatar justvanrossum avatar roberto-arista 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

Watchers

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

compositor's Issues

Loading font: AttributeError: Coverage

Hi Tal,

I can't load an OTF font with compositor using the latest version of fontTools.
Sounds familiar? Are they compatible?
Thanks in advance.

Here's the traceback:

>>> font = compositor.Font('/Users/yanone/Schriften/Font Produktion/Fonts/NonameSans-Regular.otf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/font.py", line 22, in __init__
    self.loadFeatures()
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/font.py", line 117, in loadFeatures
    self.setFeatureTables(gdef, gsub, gpos)
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/layoutEngine.py", line 37, in setFeatureTables
    self.gsub = GSUB().loadFromFontTools(gsub, self.reversedCMAP, self.gdef)
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/tables.py", line 67, in loadFromFontTools
    self.LookupList = self._LookupListClass().loadFromFontTools(table.table.LookupList, gdef)
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/lookupList.py", line 27, in loadFromFontTools
    self.Lookup = [self._LookupClass().loadFromFontTools(lookup, self, gdef) for lookup in lookupList.Lookup]
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/lookupList.py", line 58, in loadFromFontTools
    obj = cls().loadFromFontTools(subtable, self)
  File "/Users/yanone/Code/svn/typesupply/compositor.git/Lib/compositor/subTablesGSUB.py", line 101, in loadFromFontTools
    self.Coverage = Coverage().loadFromFontTools(subtable.Coverage)
  File "/Library/Python/2.7/site-packages/fonttools-3.6.3.dev0-py2.7.egg/fontTools/ttLib/tables/otBase.py", line 539, in __getattr__
    raise AttributeError(attr)
AttributeError: Coverage

Right-to-left problem with "mark" GPOS

A student of mine found a problem in the FeaturePreview.roboFontExt that I traced back to Compositor, but I'm a little bit lost with how to fix it — the handling of GPOS mark positioning doesn't seem to be working properly when the text is right-to-left.

Here's an example as I visualize the problem in DrawBot using Noto Sans Hebrew as a sample font:

image

The green text is in a normal text box in DrawBot, and the marks are positioned correctly, as a control. The red text is when rightToLeft is True, the direction is correct but the positioning is off by one base character. The purple text shows that when the text is processed in the incorrect order the mark positioning is correct.

I'm also attaching my DrawBot script below if it helps with testing the problem, and I'm testing with the latest release of Noto which can be found here: https://www.google.com/get/noto/

from compositor import Font as cFont
from fontTools.pens.cocoaPen import CocoaPen

size(200, 200)

fontPath = "./NotoSansHebrew-Medium.ttf"

def drawRecords(glyphRecords):
    for record in glyphRecords:
        save()
        translate(record.xPlacement, record.yPlacement)
        glyph = f[record.glyphName]
        pen = CocoaPen(f)
        glyph.draw(pen)
        path = BezierPath()
        drawPath(pen.path)
        restore()
        translate(glyph.width)
        

# Green text in a text box,
# Correct positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("In a text box", (10, 150))

font(fontPath)
fontSize(30)
fill(0, 0.5, 0, 1)
text("בַּיִת", (100, 150)) # oooh, this line looks weird but it works



# Red text with Compositor
# rightToLeft set to True
# Correct direction, incorrect mark positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("rightToLeft = True", (10, 100))

fill(0.75, 0, 0, 1)

save()
scale(0.05, 0.05)
translate(2000, 2000)
f = cFont(fontPath)
glyphRecords = f.process(u"בַּיִת", script="hebr", rightToLeft=True)
drawRecords(glyphRecords)
restore()

# Purple text with Compositor
# rightToLeft = False
# Incorrect direction, but correct mark positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("rightToLeft = False", (10, 50))

fill(0.5, 0, 0.5, 1)

save()
scale(0.05, 0.05)
translate(2000, 1000)
f = cFont(fontPath)
glyphRecords = f.process(u"בַּיִת", script="hebr", rightToLeft=False)
drawRecords(glyphRecords)
restore()

somehow the XP and YP are different compared a pre LayoutEngine version of compositor

I was quickly testing a basic mark feature

The current version:

screen shot 2016-01-30 at 20 42 42

an older version:

screen shot 2016-01-30 at 20 46 37

this is tested with the current version of FeaturePreview.roboFontExt

The new version also leaves traceback on non existing glyphs.

Traceback (most recent call last):
  File "/Users/frederik/Documents/dev/tmt/vanilla/Lib/vanilla/vanillaEditText.py", line 11, in controlTextDidChange_
    self.action_(notification.object())
  File "/Users/frederik/Documents/dev/tmt/vanilla/Lib/vanilla/vanillaBase.py", line 210, in action_
    self.callback(sender)
  File "/Users/frederik/Documents/dev/tmt/defconAppKit/Lib/defconAppKit/controls/glyphSequenceEditText.py", line 20, in _inputCallback
    self._finalCallback(self)
  File "featurePreview.py", line 91, in glyphLineViewInputCallback
  File "featurePreview.py", line 189, in updateGlyphLineView
  File "/Users/frederik/Documents/dev/typeSupply/compositor/Lib/compositor/font.py", line 157, in process
    glyphRecord.advanceWidth += self[glyphRecord.glyphName].width
  File "/Users/frederik/Documents/dev/typeSupply/compositor/Lib/compositor/font.py", line 130, in __getitem__
    glyph = self.glyphSet[name]
  File "/Users/frederik/Documents/dev/fonttools/Lib/fontTools/ttLib/__init__.py", line 701, in __getitem__
    return self._glyphType(self, self._glyphs[glyphName], self._hmtx[glyphName])
  File "/Users/frederik/Documents/dev/fonttools/Lib/fontTools/cffLib.py", line 532, in __getitem__
    charString = self.charStrings[name]
KeyError: 'g'

Consider a global class registry.

One thing that may help with the memory footprint is to recycle duplicate ClassDef objects. As it is now, every class is fully expanded at all times. This makes sense given that I was trying to keep the code simple instead of worrying about memory when I write this library. Anyway, here's a quick sketch:

import hashlib

class _ClassDefRegistry(object):

    def __init__(self):
        self._classes = {}

    def _makeIdentifier(self, mapping):
        identifier = []
        for name, value in sorted(mapping.items()):
            identifier.append("%s %d" % (name, value))
        identifier = "\n".join(identifier)
        identifier = hashlib.md5(identifier) # this may be over-engineering
        return identifier

    def store(self, mapping):
        identifier = self._makeIdentifier(mapping)
        self._classes[identifier] = mapping
        return identifier

    def __getitem__(self, identifier):
        return self._classes[identifier]


class ClassDef(object):

    __slots__ = ["_identifier", "_classDefRegistry", "_map", "ClassFormat", "Glyphs"]

    def __init__(self, classDefRegistry):
        self._classDefRegistry = classDefRegistry
        self.ClassFormat = None

    def loadFromFontTools(self, classDef):
        self.ClassFormat = classDef.Format
        self._identifier = self._classDefRegistry.store(dict(classDef.classDefs))
        return self

    def __getitem__(self, glyphName):
        return self.Glyphs.get(glyphName, 0)

    def _get_Glyphs(self):
        return self._classDefRegistry[self._identifier]

    Glyphs = property(_get_Glyphs, doc="This is for reference only. Not for use in processing.")


# ----
# Test
# ----

class _Dummy(object):

    def __init__(self):
        self.Format = 0
        self.classDefs = {}


test = _Dummy()
letters = "abcdefghijklmnopqrstuvwxyz"
for i in range(26):
    for j in range(1, 11):
        name = letters[i] * j
        value = len(test.classDefs)
        test.classDefs[name] = value

registry = _ClassDefRegistry()
classDef = ClassDef(registry)
classDef.loadFromFontTools(test)

print classDef.Glyphs
print classDef["mmm"]

This would require some significant structural engineering so that the global registry is passed around as needed.

Examine the implementation of GPOS lookup types 3, 4, 5 & 6.

When I wrote Compositor, I didn't have any test cases for these so I implemented them following my interpretation of the spec. The spec for these is pretty complex and (as I recall) incomplete/contradictory/confusing. So, the implementation is probably not correct. Now that the .fea syntax supports these lookup types, some test cases can be built and the implementation can be validated.

The test cases need to be incremental and atomic so that only one variable is being tested at a time. A simple text format that builds an in-memory font on the fly with defcon and pushes it through feaLib is going to be the easiest way to implement this.

I need to document the meaning of the values in compositor's glyph records after GPOS processing.

  • The x/y placement values are the adjustment to the initial drawing position of the glyph.
  • the x/y advance values are adjustments to the glyph's width/height. They do not incorporate the glyphs's width/height.

The idea is that these are "pure" GPOS values, especially for the advances. In theory, this makes it easier to evaluate the results of GPOS processing. That was the original goal of compositor.

Lookup Type 3 - Cursive Attachment

Syntax
Specification

# syntax: position cursive <glyph|glyphclass> <entryAnchor> <exitAnchor>;

glyph1.width = 100
glyph1.height = 1000

glyph2.width = 300
glyph2.height = 3000

#         no exit | no entry
position cursive glyph1 <anchor NULL> <anchor NULL>;
position cursive glyph2 <anchor NULL> <anchor NULL>;
<glyph1 0 0 0 0> <glyph2 0 0 0 0>

#            exit | no entry
position cursive glyph1 <anchor NULL> <anchor 10 30>;
position cursive glyph2 <anchor NULL> <anchor NULL>;
<glyph1 0 0 0 0> <glyph2 -90 -970 ? ?>

#         no exit |    entry
position cursive glyph1 <anchor NULL> <anchor NULL>;
position cursive glyph2 <anchor 1 3> <anchor NULL>;
<glyph1 0 0 0 0> <glyph2 -1 -3 ? ?>

#            exit |    entry
position cursive glyph1 <anchor NULL> <anchor 10 30>;
position cursive glyph2 <anchor 1 3> <anchor NULL>;
<glyph1 0 0 0 0> <glyph2 -91 -973 ? ?>

# entry + no exit | no entry + exit
position cursive glyph1 <anchor 10 30> <anchor NULL>;
position cursive glyph2 <anchor NULL> <anchor 1 3>;
<glyph1 0 0 0 0> <glyph2 0 0 0 0>

Lookup Type 4 - Mark To Base Attachment

Syntax
Specification

Test Case Syntax Goes Here

Lookup Type 5 - Mark To Ligature Attachment

Syntax
Specification

Test Case Syntax Goes Here

Lookup Type 6 - Mark To Mark Attachment

Syntax
Specification

Test Case Syntax Goes Here

GlyphClassDef AttributeError: Format

  File "c:\users\admin\downloads\defcon\lib\defcon\objects\layoutEngine.py", line 207, in process
    self._updateEngine()
  File "c:\users\admin\downloads\defcon\lib\defcon\objects\layoutEngine.py", line 109, in _updateEngine
    self._layoutEngine.setFeatureTables(gdef, gsub, gpos)
  File "c:\users\admin\downloads\compositor\lib\compositor\layoutEngine.py", line 34, in setFeatureTables
    self.gdef = GDEF().loadFromFontTools(gdef)
  File "c:\users\admin\downloads\compositor\lib\compositor\tables.py", line 358, in loadFromFontTools
    self.GlyphClassDef = GlyphClassDef().loadFromFontTools(table.GlyphClassDef)
  File "c:\users\admin\downloads\compositor\lib\compositor\classDefinitionTables.py", line 30, in loadFromFontTools
    self.ClassFormat = classDef.Format
  File "C:\Program Files\Python36\lib\site-packages\fontTools\ttLib\tables\otBase.py", line 539, in __getattr__
    raise AttributeError(attr)
AttributeError: Format

@anthrotype Would you know how to resolve this?

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.