Set Rfont to some font and access its glyph methods

  • Hello guys,
    I was wondering how Rfont and RGlyph work? I can set a myFont.newGlyph(char) but I am missing something.

    from import RFont, RGlyph
    # create a font object
    myFont = RFont(showInterface=False)
    fontName = "LucidaGrande"
    char = 'A'
    glyph = myFont.newGlyph(char)

    I get, as expected:

    <RGlyph 'A' ('public.default') at 4470687248>

    but then the glyph is empty if I:


    Usually you would do

    glyph = CurrentGlyph()

    but I am working in drawBot. Can I just set this glyph to a typeface I specify and still get access to all the methods of a RGlyph() object?

  • admin

    Calling RFont(showInterface=False) in DrawBot will create a new font object, a new UFO. You can add glyph to the font object by calling `myFont.newGlyph("a"), it will return the glyph object.

    If you wish to open an existing ufo you can call: RFont(pathToUfo, showInterface=False) and get glyph data with myExistingFont["a"] (if the ufo contains a glyph).

    hope this helps!
    good luck!

  • Thank you, @frederik. That's exactly what I was wondering! I am trying to access the side bearings but what is the method for that (leftMargin, rightMargin)?

    If I use the drawBot text():

    font('Helvetica', 200)
    txt = 'ABCW'
    text(txt, (0,0))

    The spacing is perfectly rendered from the font. How does drawBot know when to use the kerning pairs for [AA], [AW]?

    If I manipulate the characters one by one and then render them, how can I use the existing font bearings to maintain proper spacing?

    I end up with this kind of nonsense:

    def drawText(txt, x, y, fSize):
      for char in txt, range(len(txt))):
            aWidth = fSize * 0.6 * i        
            if char =="A":
                aWidth += i * 40 # + (glyph.leftMargin?)
            if char =="B":
                aWidth += i * 36
            renderChar(char, x + aWidth, y, fSize)

  • hi @michelangelo, just a small note:


    RFont.newGlyph() takes a glyph name, not a unicode character.


  • admin

    mmm, maybe you have to explain what you would like to achieve?

    fontParts is a library to read and write and manipulate ufo data.

    DrawBot callback font("Helvetica"), fontSize(10) will set attributes needed while type setting some text.

    With fontParts you have access to spacing: glyph.width and kerning in the font.kerning object. I would not encourage you to build a type setter 🙂

  • How does drawBot know when to use the kerning pairs for [AA], [AW]?

    in your example Helvetica is an installed font in binary format, you can use it to set text etc. while RFont and RGlyph are normally used to edit source fonts in UFO format.

    if you want to access and manipulate glyphs of an installed font, you can do it using the BezierPath object:


    from fontPens.flattenPen import FlattenPen
    TEXT = 'abcd'
    FONTSIZE = 300
    size(800, 300)
    translate(40, 40)
    for char in TEXT:
        # get bezier shape for character
        src = BezierPath()
        src.text(char, (0, 0), fontSize=FONTSIZE)
        # modify shape using a pen
        dst = BezierPath()
        pen = FlattenPen(dst, approximateSegmentLength=60)
        # draw original shape
        # draw modified shape
        stroke(1, 0, 0)
        # get advance width
        advance = textSize(char)[0]
        # move to next character
        translate(advance, 0)

    this example uses a pen to transform the glyph, but you can also do it using your own functions.

    hope this makes sense!

  • @gferreira That seems important! Thank you!
    @frederik No, I do not want to make my typesetter, definitely. Thanks for the heads up. What Gustavo explained is what I am talking about...

    This is exactly what I need. However, my font doesn't react normally to it... The same code with the same arguments, only different fonts:

    for char in TEXT:
        src.text(char, (0, 0), font='someFont', fontSize=FONTSIZE)
        advance = textSize(char)[0] 

    Screenshot 2020-04-22 at 17.16.35.png Screenshot 2020-04-22 at 17.16.44.png

    But if I typeset it in another way, it works:

    font('someFont', fontSize=FONTSIZE)
    text(TEXT, (0, 0))

    Screenshot 2020-04-22 at 17.19.41.png

    That's why I am confused... 😑

  • @michelangelo textSize() uses the current graphics state to measure some text, so in order get the advance widths for your font, you need to set it first:

    FONTNAME = 'someFont'
    font(FONTNAME) # <-- set the font before measuring
    for char in TEXT:
        src.text(char, (0, 0), font=FONTNAME, fontSize=FONTSIZE)
        advance = textSize(char)[0] # measure using the current font


  • @gferreira Thank you! That is much clearer now. I found that in my example I have a lot of transformations and somewhere it gets weird again, but on its own it works!

    Screenshot 2020-04-22 at 18.48.30.png

Log in to reply