Drawbot issue — Using masks on components

If I export glyphs via Drawbot mask shapes have no effect on components.
Therefore decomposing them is a requirement.

Is there a method to temporarily decompose them before saving them in Drawbot and restoring source data after? What would be a good workaround/fix for this?

How you drawing in Drawbot?

Does “layer.copyDecomposedLayer()” helps?

It helped with simple shapes … but there are issues with applying masks on glyphs/components that have nested components. The decomposing seems to change the object order in an unexpected way.

Sorry in advance for being so long-winded:

Here is my first composite glyph “smiley”. It uses one component for the base circle shape, which is a universal element I share across many other icons, and on top of that is my face component.

Screenshot 2023-10-04 at 12.32.13

Next: A typical thing to happen in the icon set is adding some kind of badge to a base icon.
Now when I use a smiley in combination with this “badge” (a mask, a small circle, and a plus) the result isn’t what it should be.

When troubleshooting I noticed that If I decompose the face component inside the smiley glyph the composite glyph exports as expected.

As you can see here the mask nicely crops out from the big circle, the eyes, and the mouth, just like you would want them.

So what is the problem? Turns out that the shape order isn’t what it should be when decomposing, somehow the face shapes end up on top of the mask instead of below.
See here the shape order window. As you can see the plus is on top, then come the objects from the face, eyes, and mouth, and then the badge and the corresponding mask on top of the large base circle. How can decomposing a component that is at the bottom split into objects that are somehow distributed in the z-order in this way?

For reference here is the object order before decomposing,

here is a glyphs file to check:
Chess Glyphs - smile.glyphs (11.5 KB)

Adding the smily directly works for me. At least in Glyphs. And when Glyphs can handle it properly, we can get the same result in Drawbot:

Can you post your Drawbot code?

But if you just need a .png, .svg or .pdf, you can use the “Glyph as Image” filter. It is not as user friendly as it could be :wink: Working on it.

And try to set the category of those smilies to “Icon”.

Not sure what to expect when clicking on “glyph as image” but nothing happens …
should there be some kind of dialog?

here is my py …

from robofab.world import CurrentFont, RGlyph
import GlyphsApp
import os

height = 16
margin = 4
minMargin = 0

font = CurrentFont()
layers = GlyphsApp.Glyphs.font.selectedLayers

Scale = float(height) / float(font.info.unitsPerEm)

save_directory_svg = "/Users/wb/x/svg"  # Specify the absolute path to save the SVG files
save_directory_pdf = "/Users/wb/x/pdf"  # Specify the absolute path to save the PDF files
save_directory_png = "/Users/wb/x/png"  # Specify the absolute path to save the PNG files

for l in layers:
    ll = l.copyDecomposedLayer()
    g = RGlyph(layer=ll)
    glyph = l .parent
    tags = glyph.tags
    minX, minY, maxX, maxY = g.box
    extraSpace = 0
    offset = 0
    offsetY = 0
    offsetX = 0

    extraSpace *= Scale
    offset *= Scale
    width = margin + (g.width * Scale) + margin + extraSpace

    # Create a new PDF document for each glyph
    newPage(width, height + (2 * margin))

    # Draw transparent square
    # fill(0, 0, 0, 0)  # Set fill color with alpha (0 for transparency)
    # rect(0, 0, width, height + (2 * margin))

    fill(0, 0, 0)  # Set fill color to black
    translate(margin + offsetY, margin + offsetX)


    # Save SVG file with absolute path
    svg_filename = g.name + ".svg"
    svg_filepath = os.path.join(save_directory_svg, svg_filename)

    # Modify SVG markup to add data attribute and remove namespace declarations
    with open(svg_filepath, "r") as svg_file:
        svg_content = svg_file.read()
    svg_content = svg_content.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "")
    svg_content = svg_content.replace(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"", "")
    svg_content = svg_content.replace(" fill=\"rgb(0,0,0)\"", "")
    svg_content = svg_content.replace("\n", "").replace("\r", "").replace("  ", "")  # Remove line breaks and extra spaces

    if "<svg" in svg_content:
        tags_str = " ".join(tags)
        svg_content = svg_content.replace("<svg", '<svg data-glyph-name="' + g.name + '" data-glyph-tags="' + tags_str + '"')

    with open(svg_filepath, "w") as svg_file:

    # Save PDF file with absolute path
    pdf_filename = g.name + ".pdf"
    pdf_filepath = os.path.join(save_directory_pdf, pdf_filename)

    # Save PNG file with absolute path
    png_filename = g.name + ".png"
    png_filepath = os.path.join(save_directory_png, png_filename)

When switching the glyph category to “icon” (instead of symbol) the content gets cropped …
Is this intentional?

Yes. An icon usually lives inside a finite box so you need to set the bounds accordingly.
And there is a simper info box where you can change the width/height.
You should get a dialog like this:

an example on how to set things up:

I would build this on a 100 unit grid, then you can scale it down by 100 to get to full pixels. calculating multiple of 60 to get the width/height to line up is tedious.

clicking on glyph as image opens no dialog at least when I use it in this font file for some reason.

What could be preventing this?

Tried again … Now this

Screenshot 2023-10-05 at 16.09.40

What version of MacOS and what kind of mac do you have?

And for the drawbot question. What happens is you use


on the original layer (not the decomposed copy)?