diff options
author | Rasmus Andersson <rasmus@notion.se> | 2018-09-03 22:55:49 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2018-09-03 22:55:49 +0300 |
commit | c833e252c925e8dd68108660710ca835d95daa6f (patch) | |
tree | 6b2e28264ed45efd7f054e453b622098d0d875b8 /misc/pylib/robofab/objects/objectsFF.py | |
parent | 8c1a4c181ef12000179dfec541f1af87e9b03122 (diff) | |
download | inter-c833e252c925e8dd68108660710ca835d95daa6f.tar.xz |
Major overhaul, moving from UFO2 to Glyphs and UFO3, plus a brand new and much simpler fontbuild
Diffstat (limited to 'misc/pylib/robofab/objects/objectsFF.py')
-rw-r--r-- | misc/pylib/robofab/objects/objectsFF.py | 1253 |
1 files changed, 0 insertions, 1253 deletions
diff --git a/misc/pylib/robofab/objects/objectsFF.py b/misc/pylib/robofab/objects/objectsFF.py deleted file mode 100644 index 4ed6aae1e..000000000 --- a/misc/pylib/robofab/objects/objectsFF.py +++ /dev/null @@ -1,1253 +0,0 @@ - - -__DEBUG__ = True -__version__ = "0.2" - -""" - RoboFab API Objects for FontForge - http://fontforge.sourceforge.net - - FontForge python docs: - http://fontforge.sourceforge.net/python.html - - Note: This is dead. EvB: "objectsFF.py is very dead and should only serve as an example of "dead" - - History - Version zero. May 2007. EvB - Experiment to see how far the API can be made to work. - - 0.1 extended testing and comparisons for attributes. - 0.2 checked into svn. Still quite raw. Lots of print statements and tests at the end. - - Notes - This code is best used with fontforge compiled as a python extension. - - FontForge Python API: - __doc__ - str(object) -> string - - Return a nice string representation of the object. - If the argument is a string, the return value is the same object. - - __file__ - str(object) -> string - - Return a nice string representation of the object. - If the argument is a string, the return value is the same object. - - __name__ - str(object) -> string - - Return a nice string representation of the object. - If the argument is a string, the return value is the same object. - - activeFont - If invoked from the UI, this returns the currently active font. When not in UI this returns None - - activeFontInUI - If invoked from the UI, this returns the currently active font. When not in UI this returns None - - activeGlyph - If invoked from the UI, this returns the currently active glyph (or None) - - ask - Pops up a dialog asking the user a question and providing a set of buttons for the user to reply with - - askChoices - Pops up a dialog asking the user a question and providing a scrolling list for the user to reply with - - askString - Pops up a dialog asking the user a question and providing a textfield for the user to reply with - - contour - fontforge Contour objects - - contouriter - None - - cvt - fontforge cvt objects - - defaultOtherSubrs - Use FontForge's default "othersubrs" functions for Type1 fonts - - font - FontForge Font object - - fontiter - None - - fonts - Returns a tuple of all loaded fonts - - fontsInFile - Returns a tuple containing the names of any fonts in an external file - - getPrefs - Get FontForge preference items - - glyph - FontForge GlyphPen object - - glyphPen - FontForge Glyph object - - hasSpiro - Returns whether this fontforge has access to Raph Levien's spiro package - - hasUserInterface - Returns whether this fontforge session has a user interface (True if it has opened windows) or is just running a script (False) - - hooks - dict() -> new empty dictionary. - dict(mapping) -> new dictionary initialized from a mapping object's - (key, value) pairs. - dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v - dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2) - - layer - fontforge Layer objects - - layeriter - None - - loadEncodingFile - Load an encoding file into the list of encodings - - loadNamelist - Load a namelist into the list of namelists - - loadNamelistDir - Load a directory of namelist files into the list of namelists - - loadPlugin - Load a FontForge plugin - - loadPluginDir - Load a directory of FontForge plugin files - - loadPrefs - Load FontForge preference items - - logWarning - Adds a non-fatal message to the Warnings window - - open - Opens a font and returns it - - openFilename - Pops up a file picker dialog asking the user for a filename to open - - parseTTInstrs - Takes a string and parses it into a tuple of truetype instruction bytes - - point - fontforge Point objects - - postError - Pops up an error dialog box with the given title and message - - postNotice - Pops up an notice window with the given title and message - - preloadCidmap - Load a cidmap file - - printSetup - Prepare to print a font sample (select default printer or file, page size, etc.) - - private - FontForge private dictionary - - privateiter - None - - readOtherSubrsFile - Read from a file, "othersubrs" functions for Type1 fonts - - registerImportExport - Adds an import/export spline conversion module - - registerMenuItem - Adds a menu item (which runs a python script) to the font or glyph (or both) windows -- in the Tools menu - - saveFilename - Pops up a file picker dialog asking the user for a filename to use for saving - - savePrefs - Save FontForge preference items - - selection - fontforge selection objects - - setPrefs - Set FontForge preference items - - spiroCorner - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - spiroG2 - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - spiroG4 - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - spiroLeft - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - spiroOpen - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - spiroRight - int(x[, base]) -> integer - - Convert a string or number to an integer, if possible. A floating point - argument will be truncated towards zero (this does not include a string - representation of a floating point number!) When converting a string, use - the optional base. It is an error to supply a base when converting a - non-string. If the argument is outside the integer range a long object - will be returned instead. - - unParseTTInstrs - Takes a tuple of truetype instruction bytes and converts to a human readable string - - unicodeFromName - Given a name, look it up in the namelists and find what unicode code point it maps to (returns -1 if not found) - - version - Returns a string containing the current version of FontForge, as 20061116 - - - - -Problems: - XXX: reading glif from UFO: is the contour order changed in some way? - - -ToDo: - - segments ? - - -""" - -import os -from robofab.objects.objectsBase import BaseFont, BaseGlyph, BaseContour, BaseSegment,\ - BasePoint, BaseBPoint, BaseAnchor, BaseGuide, BaseComponent, BaseKerning, BaseInfo, BaseGroups, BaseLib,\ - roundPt, addPt, _box,\ - MOVE, LINE, CORNER, CURVE, QCURVE, OFFCURVE,\ - relativeBCPIn, relativeBCPOut, absoluteBCPIn, absoluteBCPOut - -from robofab.objects.objectsRF import RGlyph as _RGlyph - -import fontforge -import psMat - - -# a list of attributes that are to be copied when copying a glyph. -# this is used by glyph.copy and font.insertGlyph -GLYPH_COPY_ATTRS = [ - "name", - "width", - "unicodes", - "note", - "lib", - ] - - - -def CurrentFont(): - if fontforge.hasUserInterface(): - _font = fontforge.activeFontInUI() - return RFont(_font) - if __DEBUG__: - print "CurrentFont(): fontforge not running with user interface," - return None - -def OpenFont(fontPath): - obj = fontforge.open(fontPath) - if __DEBUG__: - print "OpenFont", fontPath - print "result:", obj - return RFont(obj) - -def NewFont(fontPath=None): - _font = fontforge.font() - if __DEBUG__: - print "NewFont", fontPath - print "result:", _font - return RFont(_font) - - - - -class RFont(BaseFont): - def __init__(self, font=None): - if font is None: - # make a new font - pass - else: - self._object = font - - # ----------------------------------------------------------------- - # - # access - - def keys(self): - """FF implements __iter__ for the font object - better?""" - return [n.glyphname for n in self._object.glyphs()] - - def has_key(self, glyphName): - return glyphName in self - - def _get_info(self): - return RInfo(self._object) - - info = property(_get_info, doc="font info object") - - def __iter__(self): - for glyphName in self.keys(): - yield self.getGlyph(glyphName) - - - # ----------------------------------------------------------------- - # - # file - - def _get_path(self): - return self._object.path - - path = property(_get_path, doc="path of this file") - - def __contains__(self, glyphName): - return glyphName in self.keys() - - def save(self, path=None): - """Save this font as sfd file. - XXX: how to set a sfd path if is none - """ - if path is not None: - # trying to save it somewhere else - _path = path - else: - _path = self.path - if os.path.splitext(_path)[-1] != ".sfd": - _path = os.path.splitext(_path)[0]+".sfd" - if __DEBUG__: - print "RFont.save() to", _path - self._object.save(_path) - - def naked(self): - return self._object - - def close(self): - if __DEBUG__: - print "RFont.close()" - self._object.close() - - - # ----------------------------------------------------------------- - # - # generate - - def dummyGeneratePreHook(self, *args): - print "dummyGeneratePreHook", args - - def dummyGeneratePostHook(self, *args): - print "dummyGeneratePostHook", args - - def generate(self, outputType, path=None): - """ - generate the font. outputType is the type of font to ouput. - --Ouput Types: - 'pctype1' : PC Type 1 font (binary/PFB) - 'pcmm' : PC MultipleMaster font (PFB) - 'pctype1ascii' : PC Type 1 font (ASCII/PFA) - 'pcmmascii' : PC MultipleMaster font (ASCII/PFA) - 'unixascii' : UNIX ASCII font (ASCII/PFA) - 'mactype1' : Mac Type 1 font (generates suitcase and LWFN file) - 'otfcff' : PS OpenType (CFF-based) font (OTF) - 'otfttf' : PC TrueType/TT OpenType font (TTF) - 'macttf' : Mac TrueType font (generates suitcase) - 'macttdfont' : Mac TrueType font (generates suitcase with resources in data fork) - (doc adapted from http://dev.fontlab.net/flpydoc/) - - path can be a directory or a directory file name combo: - path="DirectoryA/DirectoryB" - path="DirectoryA/DirectoryB/MyFontName" - if no path is given, the file will be output in the same directory - as the vfb file. if no file name is given, the filename will be the - vfb file name with the appropriate suffix. - """ - - extensions = { - 'pctype1': 'pfm', - 'otfcff': 'otf', - } - - if __DEBUG__: - print "font.generate", outputType, path - - # set pre and post hooks (necessary?) - temp = getattr(self._object, "temporary") - if temp is None: - self._object.temporary = {} - else: - if type(self._object.temporary)!=dict: - self._object.temporary = {} - self._object.temporary['generateFontPreHook'] = self.dummyGeneratePreHook - self._object.temporary['generateFontPostHook'] = self.dummyGeneratePostHook - - # make a path for the destination - if path is None: - fileName = os.path.splitext(os.path.basename(self.path))[0] - dirName = os.path.dirname(self.path) - extension = extensions.get(outputType) - if extension is not None: - fileName = "%s.%s"%(fileName, extension) - else: - if __DEBUG__: - print "can't generate font in %s format"%outputType - return - path = os.path.join(dirName, fileName) - - # prepare OTF fields - generateFlags = [] - generateFlags.append('opentype') - # generate - self._object.generate(filename=path, flags=generateFlags) - if __DEBUG__: - print "font.generate():", path - return path - - - # ----------------------------------------------------------------- - # - # kerning stuff - - def _get_kerning(self): - kerning = {} - f = self._object - for g in f.glyphs: - for p in g.kerning: - try: - key = (g.name, f[p.key].name) - kerning[key] = p.value - except AttributeError: pass #catch for TT exception - rk = RKerning(kerning) - rk.setParent(self) - return rk - - kerning = property(_get_kerning, doc="a kerning object") - - # ----------------------------------------------------------------- - # - # glyph stuff - - def getGlyph(self, glyphName): - try: - ffGlyph = self._object[glyphName] - except TypeError: - print "font.getGlyph, can't find glyphName, returning new glyph" - return self.newGlyph(glyphName) - glyph = RGlyph(ffGlyph) - glyph.setParent(self) - return glyph - - def newGlyph(self, glyphName, clear=True): - """Make a new glyph - - Notes: not sure how to make a new glyph without an encoded name. - createChar() seems to be intended for that, but when I pass it -1 - for the unicode, it complains that it wants -1. Perhaps a bug? - """ - # is the glyph already there? - glyph = None - if glyphName in self: - if clear: - self._object[glyphName].clear() - return self[glyphName] - else: - # is the glyph in an encodable place: - slot = self._object.findEncodingSlot(glyphName) - if slot == -1: - # not encoded - print "font.newGlyph: unencoded slot", slot, glyphName - glyph = self._object.createChar(-1, glyphName) - else: - glyph = self._object.createMappedChar(glyphName) - glyph = RGlyph(self._object[glyphName]) - glyph.setParent(self) - return glyph - - def removeGlyph(self, glyphName): - self._object.removeGlyph(glyphName) - - - - -class RGlyph(BaseGlyph): - """Fab wrapper for FF Glyph object""" - def __init__(self, ffGlyph=None): - if ffGlyph is None: - raise RoboFabError - self._object = ffGlyph - # XX anchors seem to be supported, but in a different way - # XX so, I will ignore them for now to get something working. - self.anchors = [] - self.lib = {} - - def naked(self): - return self._object - - def setChanged(self): - self._object.changed() - - - # ----------------------------------------------------------------- - # - # attributes - - def _get_name(self): - return self._object.glyphname - def _set_name(self, value): - self._object.glyphname = value - name = property(_get_name, _set_name, doc="name") - - def _get_note(self): - return self._object.comment - def _set_note(self, note): - self._object.comment = note - note = property(_get_note, _set_note, doc="note") - - def _get_width(self): - return self._object.width - def _set_width(self, width): - self._object.width = width - width = property(_get_width, _set_width, doc="width") - - def _get_leftMargin(self): - return self._object.left_side_bearing - def _set_leftMargin(self, leftMargin): - self._object.left_side_bearing = leftMargin - leftMargin = property(_get_leftMargin, _set_leftMargin, doc="leftMargin") - - def _get_rightMargin(self): - return self._object.right_side_bearing - def _set_rightMargin(self, rightMargin): - self._object.right_side_bearing = rightMargin - rightMargin = property(_get_rightMargin, _set_rightMargin, doc="rightMargin") - - def _get_unicodes(self): - return [self._object.unicode] - def _set_unicodes(self, unicodes): - assert len(unicodes)==1 - self._object.unicode = unicodes[0] - unicodes = property(_get_unicodes, _set_unicodes, doc="unicodes") - - def _get_unicode(self): - return self._object.unicode - def _set_unicode(self, unicode): - self._object.unicode = unicode - unicode = property(_get_unicode, _set_unicode, doc="unicode") - - def _get_box(self): - bounds = self._object.boundingBox() - return bounds - box = property(_get_box, doc="the bounding box of the glyph: (xMin, yMin, xMax, yMax)") - - def _get_mark(self): - """color of the glyph box in the font view. This accepts a 6 hex digit number. - - XXX the FL implementation accepts a - """ - import colorsys - r = (self._object.color&0xff0000)>>16 - g = (self._object.color&0xff00)>>8 - g = (self._object.color&0xff)>>4 - return colorsys.rgb_to_hsv( r, g, b)[0] - - def _set_mark(self, markColor=-1): - import colorsys - self._object.color = colorSys.hsv_to_rgb(markColor, 1, 1) - - mark = property(_get_mark, _set_mark, doc="the color of the glyph box in the font view") - - - # ----------------------------------------------------------------- - # - # pen, drawing - - def getPen(self): - return self._object.glyphPen() - - def __getPointPen(self): - """Return a point pen. - - Note: FontForge doesn't support segment pen, so return an adapter. - """ - from robofab.pens.adapterPens import PointToSegmentPen - segmentPen = self._object.glyphPen() - return PointToSegmentPen(segmentPen) - - def getPointPen(self): - from robofab.pens.rfUFOPen import RFUFOPointPen - pen = RFUFOPointPen(self) - #print "getPointPen", pen, pen.__class__, dir(pen) - return pen - - def draw(self, pen): - """draw - - """ - self._object.draw(pen) - pen = None - - def drawPoints(self, pen): - """drawPoints - - Note: FontForge implements glyph.draw, but not glyph.drawPoints. - """ - from robofab.pens.adapterPens import PointToSegmentPen, SegmentToPointPen - adapter = SegmentToPointPen(pen) - self._object.draw(adapter) - pen = None - - def appendGlyph(self, other): - pen = self.getPen() - other.draw(pen) - - # ----------------------------------------------------------------- - # - # glyphmath - - def round(self): - self._object.round() - - def _getMathDestination(self): - from robofab.objects.objectsRF import RGlyph as _RGlyph - return _RGlyph() - - def _mathCopy(self): - # copy self without contour, component and anchor data - glyph = self._getMathDestination() - glyph.name = self.name - glyph.unicodes = list(self.unicodes) - glyph.width = self.width - glyph.note = self.note - glyph.lib = dict(self.lib) - return glyph - - def __mul__(self, factor): - if __DEBUG__: - print "glyphmath mul", factor - return self.copy() *factor - - __rmul__ = __mul__ - - def __sub__(self, other): - if __DEBUG__: - print "glyphmath sub", other, other.__class__ - return self.copy() - other.copy() - - def __add__(self, other): - if __DEBUG__: - print "glyphmath add", other, other.__class__ - return self.copy() + other.copy() - - def getParent(self): - return self - - def copy(self, aParent=None): - """Make a copy of this glyph. - Note: the copy is not a duplicate fontlab glyph, but - a RF RGlyph with the same outlines. The new glyph is - not part of the fontlab font in any way. Use font.appendGlyph(glyph) - to get it in a FontLab glyph again.""" - from robofab.objects.objectsRF import RGlyph as _RGlyph - newGlyph = _RGlyph() - newGlyph.appendGlyph(self) - for attr in GLYPH_COPY_ATTRS: - value = getattr(self, attr) - setattr(newGlyph, attr, value) - parent = self.getParent() - if aParent is not None: - newGlyph.setParent(aParent) - elif self.getParent() is not None: - newGlyph.setParent(self.getParent()) - return newGlyph - - def _get_contours(self): - # find the contour data and wrap it - - """get the contours in this glyph""" - contours = [] - for n in range(len(self._object.foreground)): - item = self._object.foreground[n] - rc = RContour(item, n) - rc.setParent(self) - contours.append(rc) - #print contours - return contours - - contours = property(_get_contours, doc="allow for iteration through glyph.contours") - - # ----------------------------------------------------------------- - # - # transformations - - def move(self, (x, y)): - matrix = psMat.translate((x,y)) - self._object.transform(matrix) - - def scale(self, (x, y), center=(0,0)): - matrix = psMat.scale(x,y) - self._object.transform(matrix) - - def transform(self, matrix): - self._object.transform(matrix) - - def rotate(self, angle, offset=None): - matrix = psMat.rotate(angle) - self._object.transform(matrix) - - def skew(self, angle, offset=None): - matrix = psMat.skew(angle) - self._object.transform(matrix) - - # ----------------------------------------------------------------- - # - # components stuff - - def decompose(self): - self._object.unlinkRef() - - # ----------------------------------------------------------------- - # - # unicode stuff - - def autoUnicodes(self): - if __DEBUG__: - print "objectsFF.RGlyph.autoUnicodes() not implemented yet." - - # ----------------------------------------------------------------- - # - # contour stuff - - def removeOverlap(self): - self._object.removeOverlap() - - def correctDirection(self, trueType=False): - # no option for trueType, really. - self._object.correctDirection() - - def clear(self): - self._object.clear() - - def __getitem__(self, index): - return self.contours[index] - - -class RContour(BaseContour): - def __init__(self, contour, index=None): - self._object = contour - self.index = index - - def _get_points(self): - pts = [] - for pt in self._object: - wpt = RPoint(pt) - wpt.setParent(self) - pts.append(wpt) - return pts - - points = property(_get_points, doc="get contour points") - - def _get_box(self): - return self._object.boundingBox() - - box = property(_get_box, doc="get contour bounding box") - - def __len__(self): - return len(self._object) - - def __getitem__(self, index): - return self.points[index] - - - -class RPoint(BasePoint): - - def __init__(self, pointObject): - self._object = pointObject - - def _get_x(self): - return self._object.x - - def _set_x(self, value): - self._object.x = value - - x = property(_get_x, _set_x, doc="") - - def _get_y(self): - return self._object.y - - def _set_y(self, value): - self._object.y = value - - y = property(_get_y, _set_y, doc="") - - def _get_type(self): - if self._object.on_curve == 0: - return OFFCURVE - - # XXX not always curve - return CURVE - - def _set_type(self, value): - self._type = value - self._hasChanged() - - type = property(_get_type, _set_type, doc="") - - def __repr__(self): - font = "unnamed_font" - glyph = "unnamed_glyph" - contourIndex = "unknown_contour" - contourParent = self.getParent() - if contourParent is not None: - try: - contourIndex = `contourParent.index` - except AttributeError: pass - glyphParent = contourParent.getParent() - if glyphParent is not None: - try: - glyph = glyphParent.name - except AttributeError: pass - fontParent = glyphParent.getParent() - if fontParent is not None: - try: - font = fontParent.info.fullName - except AttributeError: pass - return "<RPoint for %s.%s[%s]>"%(font, glyph, contourIndex) - - -class RInfo(BaseInfo): - def __init__(self, font): - BaseInfo.__init__(self) - self._object = font - - def _get_familyName(self): - return self._object.familyname - def _set_familyName(self, value): - self._object.familyname = value - familyName = property(_get_familyName, _set_familyName, doc="familyname") - - def _get_fondName(self): - return self._object.fondname - def _set_fondName(self, value): - self._object.fondname = value - fondName = property(_get_fondName, _set_fondName, doc="fondname") - - def _get_fontName(self): - return self._object.fontname - def _set_fontName(self, value): - self._object.fontname = value - fontName = property(_get_fontName, _set_fontName, doc="fontname") - - # styleName doesn't have a specific field, FF has a whole sfnt dict. - # implement fullName because a repr depends on it - def _get_fullName(self): - return self._object.fullname - def _set_fullName(self, value): - self._object.fullname = value - fullName = property(_get_fullName, _set_fullName, doc="fullname") - - def _get_unitsPerEm(self): - return self._object.em - def _set_unitsPerEm(self, value): - self._object.em = value - unitsPerEm = property(_get_unitsPerEm, _set_unitsPerEm, doc="unitsPerEm value") - - def _get_ascender(self): - return self._object.ascent - def _set_ascender(self, value): - self._object.ascent = value - ascender = property(_get_ascender, _set_ascender, doc="ascender value") - - def _get_descender(self): - return -self._object.descent - def _set_descender(self, value): - self._object.descent = -value - descender = property(_get_descender, _set_descender, doc="descender value") - - def _get_copyright(self): - return self._object.copyright - def _set_copyright(self, value): - self._object.copyright = value - copyright = property(_get_copyright, _set_copyright, doc="copyright") - - - -class RKerning(BaseKerning): - - """ Object representing the kerning. - This is going to need some thinking about. - """ - - -__all__ = [ 'RFont', 'RGlyph', 'RContour', 'RPoint', 'RInfo', - 'OpenFont', 'CurrentFont', 'NewFont', 'CurrentFont' - ] - - - -if __name__ == "__main__": - import os - from robofab.objects.objectsRF import RFont as _RFont - from sets import Set - - def dumpFontForgeAPI(testFontPath, printModule=False, - printFont=False, printGlyph=False, - printLayer=False, printContour=False, printPoint=False): - def printAPI(item, name): - print - print "-"*80 - print "API of", item - names = dir(item) - names.sort() - print - - if printAPI: - for n in names: - print - print "%s.%s"%(name, n) - try: - print getattr(item, n).__doc__ - except: - print "# error showing", n - # module - if printModule: - print "module file:", fontforge.__file__ - print "version:", fontforge.version() - print "module doc:", fontforge.__doc__ - print "has User Interface:", fontforge.hasUserInterface() - print "has Spiro:", fontforge.hasSpiro() - printAPI(fontforge, "fontforge") - - # font - fontObj = fontforge.open(testFontPath) - if printFont: - printAPI(fontObj, "font") - - # glyph - glyphObj = fontObj["A"] - if printGlyph: - printAPI(glyphObj, "glyph") - - # layer - layerObj = glyphObj.foreground - if printLayer: - printAPI(layerObj, "layer") - - # contour - contourObj = layerObj[0] - if printContour: - printAPI(contourObj, "contour") - - # point - if printPoint: - pointObj = contourObj[0] - printAPI(pointObj, "point") - - - # other objects - penObj = glyphObj.glyphPen() - printAPI(penObj, "glyphPen") - - # use your own paths here. - demoRoot = "/Users/erik/Develop/Mess/FontForge/objectsFF_work/" - UFOPath = os.path.join(demoRoot, "Test.ufo") - SFDPath = os.path.join(demoRoot, "Test_realSFD2.sfd") - - #dumpFontForgeAPI(UFOPath, printPoint=True) - - # should return None - CurrentFont() - - def compareAttr(obj1, obj2, attrName, isMethod=False): - if isMethod: - a = getattr(obj1, attrName)() - b = getattr(obj2, attrName)() - else: - a = getattr(obj1, attrName) - b = getattr(obj2, attrName) - if a == b and a is not None and b is not None: - print "\tattr %s ok"%attrName, a - return True - else: - print "\t?\t%s error:"%attrName, "%s:"%obj1.__class__, a, "%s:"%obj2.__class__, b - return False - - f = OpenFont(UFOPath) - #f = OpenFont(SFDPath) - ref = _RFont(UFOPath) - - if False: - print - print "test font attributes" - compareAttr(f, ref, "path") - - a = Set(f.keys()) - b = Set(ref.keys()) - print "glyphs in ref, not in f", b.difference(a) - print "glyphs in f, not in ref", a.difference(b) - - print "A" in f, "A" in ref - print f.has_key("A"), ref.has_key("A") - - print - print "test font info attributes" - compareAttr(f.info, ref.info, "ascender") - compareAttr(f.info, ref.info, "descender") - compareAttr(f.info, ref.info, "unitsPerEm") - compareAttr(f.info, ref.info, "copyright") - compareAttr(f.info, ref.info, "fullName") - compareAttr(f.info, ref.info, "familyName") - compareAttr(f.info, ref.info, "fondName") - compareAttr(f.info, ref.info, "fontName") - - # crash - f.save() - - otfOutputPath = os.path.join(demoRoot, "test_ouput.otf") - ufoOutputPath = os.path.join(demoRoot, "test_ouput.ufo") - # generate without path, should end up in the source folder - - f['A'].removeOverlap() - f.generate('otfcff') #, otfPath) - f.generate('pctype1') #, otfPath) - - # generate with path. Type is taken from the extension. - f.generate('otfcff', otfOutputPath) #, otfPath) - f.generate(None, ufoOutputPath) #, otfPath) - - featurePath = os.path.join(demoRoot, "testFeatureOutput.fea") - f.naked().generateFeatureFile(featurePath) - - if False: - # new glyphs - # unencoded - print "new glyph: unencoded", f.newGlyph("test_unencoded_glyph") - # encoded - print "new glyph: encoded", f.newGlyph("Adieresis") - # existing - print "new glyph: existing", f.newGlyph("K") - - print - print "test glyph attributes" - compareAttr(f['A'], ref['A'], "width") - compareAttr(f['A'], ref['A'], "unicode") - compareAttr(f['A'], ref['A'], "name") - compareAttr(f['A'], ref['A'], "box") - compareAttr(f['A'], ref['A'], "leftMargin") - compareAttr(f['A'], ref['A'], "rightMargin") - - if False: - print - print "comparing glyph digests" - failed = [] - for n in f.keys(): - g1 = f[n] - #g1.round() - g2 = ref[n] - #g2.round() - d1 = g1._getDigest() - d2 = g2._getDigest() - if d1 != d2: - failed.append(n) - #print "f: ", d1 - #print "ref: ", d2 - print "digest failed for %s"%". ".join(failed) - - g3 = f['A'] *.333 - print g3 - print g3._getDigest() - f.save() - - if False: - print - print "test contour attributes" - compareAttr(f['A'].contours[0], ref['A'].contours[0], "index") - - #for c in f['A'].contours: - # for p in c.points: - # print p, p.type - - # test with a glyph with just 1 contour so we can be sure we're comparing the same thing - compareAttr(f['C'].contours[0], ref['C'].contours[0], "box") - compareAttr(f['C'].contours[0], ref['C'].contours[0], "__len__", isMethod=True) - - ptf = f['C'].contours[0].points[0] - ptref = ref['C'].contours[0].points[0] - print "x, y", (ptf.x, ptf.y) == (ptref.x, ptref.y), (ptref.x, ptref.y) - print 'type', ptf.type, ptref.type - - print "point inside", f['A'].pointInside((50,10)), ref['A'].pointInside((50,10)) - - - print ref.kerning.keys() - - class GlyphLookupWrapper(dict): - """A wrapper for the lookups / subtable data in a FF glyph. - A lot of data is stored there, so it helps to have something to sort things out. - """ - def __init__(self, ffGlyph): - self._object = ffGlyph - self.refresh() - - def __repr__(self): - return "<GlyphLookupWrapper for %s, %d keys>"%(self._object.glyphname, len(self)) - - def refresh(self): - """Pick some of the values apart.""" - lookups = self._object.getPosSub('*') - for t in lookups: - print 'lookup', t - lookupName = t[0] - lookupType = t[1] - if not lookupName in self: - self[lookupName] = [] - self[lookupName].append(t[1:]) - - def getKerning(self): - """Get a regular kerning dict for this glyph""" - d = {} - left = self._object.glyphname - for name in self.keys(): - for item in self[name]: - print 'item', item - if item[0]!="Pair": - continue - #print 'next glyph:', item[1] - #print 'first glyph x Pos:', item[2] - #print 'first glyph y Pos:', item[3] - #print 'first glyph h Adv:', item[4] - #print 'first glyph v Adv:', item[5] - - #print 'second glyph x Pos:', item[6] - #print 'second glyph y Pos:', item[7] - #print 'second glyph h Adv:', item[8] - #print 'second glyph v Adv:', item[9] - right = item[1] - d[(left, right)] = item[4] - return d - - def setKerning(self, kernDict): - """Set the values of a regular kerning dict to the lookups in a FF glyph.""" - for left, right in kernDict.keys(): - if left != self._object.glyphname: - # should we filter the dict before it gets here? - # easier just to filter it here. - continue - - - - # lets try to find the kerning - A = f['A'].naked() - positionTypes = [ "Position", "Pair", "Substitution", "AltSubs", "MultSubs","Ligature"] - print A.getPosSub('*') - #for t in A.getPosSub('*'): - # print 'lookup subtable name:', t[0] - # print 'positioning type:', t[1] - # if t[1]in positionTypes: - # print 'next glyph:', t[2] - # print 'first glyph x Pos:', t[3] - # print 'first glyph y Pos:', t[4] - # print 'first glyph h Adv:', t[5] - # print 'first glyph v Adv:', t[6] - - # print 'second glyph x Pos:', t[7] - # print 'second glyph y Pos:', t[8] - # print 'second glyph h Adv:', t[9] - # print 'second glyph v Adv:', t[10] - - gw = GlyphLookupWrapper(A) - print gw - print gw.keys() - print gw.getKerning() - - name = "'kern' Horizontal Kerning in Latin lookup 0 subtable" - item = (name, 'quoteright', 0, 0, -200, 0, 0, 0, 0, 0) - - A.removePosSub(name) - apply(A.addPosSub, item) - - - print "after", A.getPosSub('*') - - fn = f.naked() - - name = "'kern' Horizontal Kerning in Latin lookup 0" - - - print "before removing stuff", fn.gpos_lookups - print "removing stuff", fn.removeLookup(name) - print "after removing stuff", fn.gpos_lookups - - flags = () - feature_script_lang = (("kern",(("latn",("dflt")),)),) - print fn.addLookup('kern', 'gpos_pair', flags, feature_script_lang) - print fn.addLookupSubtable('kern', 'myKerning') - - - print fn.gpos_lookups - A.addPosSub('myKerning', 'A', 0, 0, -400, 0, 0, 0, 0, 0) - A.addPosSub('myKerning', 'B', 0, 0, 200, 0, 0, 0, 0, 0) - A.addPosSub('myKerning', 'C', 0, 0, 10, 0, 0, 0, 0, 0) - A.addPosSub('myKerning', 'A', 0, 0, 77, 0, 0, 0, 0, 0) - - - gw = GlyphLookupWrapper(A) - print gw - print gw.keys() - print gw.getKerning() - |