This example shows how to register a defcon.Glyph representation that outputs a NSImage. The NSImage is then drawn with merz on the glyph editor.

from defcon import Glyph, registerRepresentationFactory
import drawBot as db
from mojo.events import postEvent
from mojo.roboFont import OpenWindow
from mojo.subscriber import (
    Subscriber,
    WindowController,
    registerGlyphEditorSubscriber,
    registerSubscriberEvent,
    unregisterGlyphEditorSubscriber,
)
from vanilla import FloatingWindow, PopUpButton, TextBox


def blurredGlyphFactory(glyph, radius=1):
    glyph = glyph.asFontParts()

    bounds = glyph.bounds
    if not bounds:
        return (0, 0), (0, 0), None

    xMin, yMin, xMax, yMax = glyph.bounds
    width = xMax - xMin
    height = yMax - yMin

    db.newDrawing()
    db.newPage(width, height)
    db.translate(-xMin, -yMin)

    bezierPath = db.BezierPath(glyphSet=glyph.layer)
    glyph.draw(bezierPath)

    imObj = db.ImageObject()
    with imObj:
        db.size(width+radius*2, height+radius*2)
        db.drawPath(bezierPath)

    imObj.gaussianBlur(radius=radius)
    x, y = imObj.offset()
    db.image(imObj, (x, y))

    nsImage = db.saveImage("NSImage")
    db.endDrawing()

    return (xMin, yMin), (width, height), nsImage


class BlurredSubscriber(Subscriber):

    debug = True
    controller = None

    glyphEditorDidSetGlyphDelay = 0
    glyphEditorGlyphDidChangeOutlineDelay = 0

    def build(self):
        self.glyphEditor = self.getGlyphEditor()
        self.container = self.glyphEditor.extensionContainer(
            identifier="com.roboFont.blurredSubscriber",
            location="background",
            clear=True,
        )
        self.imageLayer = self.container.appendImageSublayer()

    def started(self):
        self.drawCells()

    def destroy(self):
        self.container.clearSublayers()

    def glyphEditorDidSetGlyph(self, info):
        self.drawCells()

    def glyphEditorGlyphDidChangeOutline(self, info):
        self.drawCells()

    def controllerDidChange(self, info):
        self.drawCells()

    def drawCells(self):
        if self.controller is None:
            return

        self.imageLayer.clearSublayers()
        radius = int(self.controller.w.popUpButton.getItem())

        glyph = self.glyphEditor.getGlyph()
        origin, size, nsImage = glyph.getRepresentation("blurredRepresentation", radius=radius)
        if nsImage:
            self.imageLayer.setSize(size)
            self.imageLayer.setPosition(origin)
            self.imageLayer.setImage(nsImage)


class BlurredController(WindowController):

    debug = True

    def build(self):
        print("BlurredController")
        self.w = FloatingWindow((120, 50), "Blurred Glyph")
        self.w.caption = TextBox((10, 14, 50, 30), "Radius:")
        self.w.popUpButton = PopUpButton(
            (65, 10, -10, 30),
            items=["5", "10", "15"],
            callback=self.popUpButtonCallback,
        )
        self.w.open()

    def started(self):
        BlurredSubscriber.controller = self
        registerGlyphEditorSubscriber(BlurredSubscriber)

    def destroy(self):
        BlurredSubscriber.controller = None
        unregisterGlyphEditorSubscriber(BlurredSubscriber)

    def popUpButtonCallback(self, sender):
        postEvent("controllerDidChange")


if __name__ == "__main__":
    registerRepresentationFactory(Glyph, "blurredRepresentation", blurredGlyphFactory)
    registerSubscriberEvent(
        subscriberEventName="controllerDidChange",
        methodName="controllerDidChange",
        lowLevelEventNames=["controllerDidChange"],
        dispatcher="roboFont",
        delay=0,
        debug=True,
    )
    OpenWindow(BlurredController)

Last edited on 01/09/2021