Glyphs as module with Drawbot

I’m trying to make some Drawbot animations using both Glyphs and Drawbot as modules.

Usually, when using the Drawbot plugin to do stuff with Glyphs’ api, I can draw a layer by doing something like:

drawPath(Layer.bezierPath)

Doing the same in a remote script like so:

import os
from drawBot import *
from Glyphs import *

path = os.path.expanduser("~/pathToMyFont")

doc = Glyphs.openDocumentWithContentsOfFile_display_(path, False)
font = doc.font()

W = H = 1080
newDrawing()
newPage(W, H)

layer = font.glyphForName_('A').layer0()
path = layer.bezierPath()
drawPath(path)

saveImage("~/Desktop/test.gif")
endDrawing()
doc.close()

Raises an AttributeError: 'NSDistantObject' object has no attribute 'getNSBezierPath'

It seems like Layer.bezierPath returns a GSSaveBezierPath that is a NSBezierPath Drawbot can take in its drawPath() method, but the bezierPath()objc method I’m using in my remote script returns a NSDIstant object that Drawbot doesn’t know about.

What method should I use to get a NSBezierPath I can pass to Drawbot methods?

Through the remove bridge, you always only get NSDistantObject. They have a thin mask that make them look like the actual objects. One would need to check the drawbot code that throws the error and check how they distinguish if the argument is an NSBezierpath or a drawbot path. I would patch drawbot to “fix” this test. Testing for .className() instead of the class might help.

It seems it all comes down to this: /drawBot/context/pdfContext.py

def _pdfPath(self, path):
    path = path.getNSBezierPath()
    for i in range(path.elementCount()):
        instruction, points = path.elementAtIndex_associatedPoints_(i)
        if instruction == AppKit.NSMoveToBezierPathElement:
            Quartz.CGContextMoveToPoint(self._pdfContext, points[0].x, points[0].y)
        elif instruction == AppKit.NSLineToBezierPathElement:
            Quartz.CGContextAddLineToPoint(self._pdfContext, points[0].x, points[0].y)
        elif instruction == AppKit.NSCurveToBezierPathElement:
            Quartz.CGContextAddCurveToPoint(self._pdfContext, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y)
        elif instruction == AppKit.NSClosePathBezierPathElement:
            Quartz.CGContextClosePath(self._pdfContext)

Not sure what to change without risking to break anything. If I remove the path.getNSBezierPath() line, I get this error:

File "/Users/joachimvu/.pyenv/versions/drawbot/lib/python3.6/site-packages/drawBot/context/pdfContext.py", line 298, in _pdfPath
    instruction, points = path.elementAtIndex_associatedPoints_(i)
TypeError: Need 2 arguments, got 1

If I pass the NSDistantObject to drawbot’s BezierPath() method, I get the same error from /drawBot/context/baseContext.py:

File "/Users/joachimvu/.pyenv/versions/drawbot/lib/python3.6/site-packages/drawBot/context/baseContext.py", line 779, in _get_contours
    instruction, pts = self._path.elementAtIndex_associatedPoints_(index)
TypeError: Need 2 arguments, got 1
``

This really needs two arguments. At least a None.

instruction, points = path.elementAtIndex_associatedPoints_(i, None)

You need one argument for each underscore.

1 Like

Thats what I don’t understand, I did not change this, that’s drawbot’s code as it is.

Maybe ask on the drawbot forum?