Easy Slants Script

Hi there.
I’m trying to write a script that creates a base for making easy slants.

I’m having some trouble with changing the ItalicAngle metric on the master.
For some reason this new_master.italicAngle = italic_angle doesn’t work?

I also can’t get the copying of the layers to work. So my new masters are empty.
font.copyInfoFrom_sourceFontMasterID_targetFontMasterID_(font, master.id, new_master.id)

And the last thing is that I keep getting an error on this code layer.slantX_Origin_doCorrection_(italic_angle, NSPoint(0, x_height_half), True)


#MenuTitle: Make Easy Slants
# -*- coding: utf-8 -*-
# Import the GlyphsApp module
from GlyphsApp import *

# Get the current font
font = Glyphs.font

# Define the italic angle
italic_angle = 9.5

# 1) Add an Axes called “Italic” in the font-info.
axis = GSAxis()
axis.name = "Italic"
axis.axisTag = "Ital"
font.axes.append(axis)

# 2) Set all the masters to "0" on the Italic axes.
for master in font.masters:
    master.axes['ital'] = 0
     
# 3) Duplicate all the masters and set the new duplicated to "1" on the italic axis.
new_masters = []
for master in font.masters:
    new_master = master.copy()
    new_master.name += " Italic"
    new_master.axes['ital'] = 1
	new_master.italicAngle = italic_angle
    new_masters.append(new_master)
    font.copyInfoFrom_sourceFontMasterID_targetFontMasterID_(font, master.id, new_master.id)
font.masters.extend(new_masters)



# 4) Duplicates all the instances and check their "Italic" checkbox in the "style linking"
for instance in list(font.instances):
    new_instance = instance.copy()
    new_instance.isItalic = True
    new_instance.linkStyle = new_instance.name
    new_instance.name += " Italic"
    new_instance.axes['ital'] = 1
    font.instances.append(new_instance)

# 5) Cursify all the glyphs in the Italic masters.
    if master.axes['ital'] == 1:
        layer = glyph.layers[master.id]
            
		 # Calculate half of the x-height
        x_height_half = master.xHeight / 2.0
            
        # Apply the italic transformation
        layer.slantX_Origin_doCorrection_(italic_angle, NSPoint(0, x_height_half), True)


# Update the font
font.updateFeatures()
font.updateMetrics()

print("Easy Slants completed successfully.")

Let me know if you spot anything else that would make the script better.

Thanks,

Andreas

Not sure why you need a new master for this script to work. I would set up the master beforehand and let the script take the upright outlines, copy it and add it to the italic layers.

But if you need to do that with a script: you need to add the master to the font first. The Metrics are connected with the font.metrics.

do you mean to use copyGlyphs:(GSFont *)sourceFont sourceFontMasterID:(NSString *)sourceFontMasterID targetFontMasterID:(NSString *)targetFontMasterID addMissing:(BOOL)addMissing?

Again I would recommend to do that beforehand.

In the latest cutting edge version, this is slantX_origin_doCorrection_checkSelection_() (note he lowercase origin.

In any case, the origin is a single float:
layer.slantX_Origin_doCorrection_(italic_angle, x_height_half, True)

Thank you so much.

Is there a reason why you would duplicate the masters manually beforehand? instead of the script doing it for you? cause I think it would be pretty cool with a script that basically would make basic slants automatically.

and is this copyGlyphs:(GSFont *)sourceFont sourceFontMasterID:(NSString *)sourceFontMasterID targetFontMasterID:(NSString *)targetFontMasterID addMissing:(BOOL)addMissing the best way to way to duplicate a master with a script, so I copy all kerning, metrics, anchors and so forth?

because you probably need to run that script more than once while woking on that font (adding new glyphs …). A script should do one thing, otherwise it is not flexibly enough.

The copyGlyphs: method is copying the glyphs, the one you had is copying everything else.

Okay thanks.

So it would look like this, for a duplicate of the masters?

for master in new_masters:
    sourceFont = font
    sourceFontMasterID = master.id
    targetFontMasterID = master.id
    addMissing = True  # Add missing glyphs from source to target
    font.copyGlyphs_sourceFont_sourceFontMasterID_targetFontMasterID_addMissing_(sourceFont, sourceFontMasterID, targetFontMasterID, addMissing)

Or?

The master ID needs to be unique for all masters. I need a bit more context but what is there doesn’t seem to make much sense.

Sorry for my bad python skills. Here you have some more context.

# MenuTitle: Make Easy Slants
# -*- coding: utf-8 -*-
# Import the GlyphsApp module
from GlyphsApp import *

# Get the current font
font = Glyphs.font

# Define the italic angle
italic_angle = 9.5

# 1) Add an Axes called “Italic” in the font-info.
axis = GSAxis()
axis.name = "Italic"
axis.axisTag = "Ital"
font.axes.append(axis)

# 2) Set all the masters to "0" on the Italic axes.
for master in font.masters:
    master.axes['ital'] = 0

# 3) Duplicate all the masters and set the new duplicated to "1" on the italic axis.
new_masters = []
for master in font.masters:
    new_master = master.copy()
    new_master.name += " Italic"
    new_master.axes['ital'] = 1
    new_masters.append(new_master)

# Add the new masters to the font before setting italic angle
font.masters.extend(new_masters)

# Set the italic angle for the new masters
for new_master in new_masters:
    new_master.italicAngle = italic_angle

# 4) Duplicates all the instances and check their "Italic" checkbox in the "style linking"
for instance in list(font.instances):
    new_instance = instance.copy()
    new_instance.isItalic = True
    new_instance.linkStyle = new_instance.name
    new_instance.name += " Italic"
    new_instance.axes['ital'] = 1
    font.instances.append(new_instance)


#5) Copy glyphs from source font to target font for each master
for master in new_masters:
    sourceFont = font
    sourceFontMasterID = master.id
    targetFontMasterID = master.id
    addMissing = True  # Add missing glyphs from source to target
    font.copyGlyphs_sourceFont_sourceFontMasterID_targetFontMasterID_addMissing_(sourceFont, sourceFontMasterID, targetFontMasterID, addMissing)

# 5) Cursify all the glyphs in the Italic masters.
for master in new_masters:
    if master.axes['ital'] == 1:
        for glyph in font.glyphs:
            layer = glyph.layers[master.id]
            # Calculate half of the x-height
            x_height_half = master.xHeight / 2.0
            # Apply the italic transformation
            layer.slantX_origin_doCorrection_checkSelection_(italic_angle, x_height_half, True)


# Update the font metrics
font.metrics.updateMetrics()

# Update the font features
font.updateFeatures()


print("Easy Slants completed successfully.")

You can use a UUID to generate a unique master ID for your master copy:

from uuid import uuid4

# ...

targetFontMasterID = str(uuid4())

Thanks for the response Florian :slight_smile:
But I think I’m completely lost now. :sweat_smile: I’m just trying to duplicate my masters (with kerning, metrics, anchors and everything) and set the new masters with an italicAngle metric and Cursify them.

Here is a minimal setup to copy a font master with its contents:

from uuid import uuid4

font = Font

# the master that you want to copy
master = font.masters[0]

# the copy of the source master
new_master = master.copy()

# change the id (required) and name (optional) of the new master
# before adding it to the font
new_master.id = str(uuid4())
new_master.name += " Italic"
font.masters.append(new_master)

# the copy of the master only contains metadata (like metrics
# and axis values), now copy contents from source master:
addMissing = True  # Add missing glyphs from source to target
font.copyGlyphs_sourceFontMasterID_targetFontMasterID_addMissing_(font, master.id, new_master.id, addMissing)

(Note that the _sourceFont in the long method name is not needed.)

2 Likes

Thanks! Now it works! and it’s pretty cool.
Is there a way to avoid Cursifying components that has already been Cursified?
Maybe in this layer.slantX_origin_doCorrection_checkSelection_(italic_angle, x_height_half, True, True)

Here is the full code:

# MenuTitle: Make Easy Slants
# -*- coding: utf-8 -*-
# Import the GlyphsApp module
from GlyphsApp import *

from uuid import uuid4

# Get the current font
font = Glyphs.font

# Define the italic angle
italic_angle = 9.5

# 1) Add an Axes called “Italic” in the font-info.
axis = GSAxis()
axis.name = "Italic"
axis.axisTag = "Ital"
font.axes.append(axis)

# 2) Set all the masters to "0" on the Italic axes.
for master in font.masters:
    master.axes['ital'] = 0

# 3) Duplicate all the masters and set the new duplicated to "1" on the italic axis.
new_masters = []
for master in font.masters:
    new_master = master.copy()
    new_master.id = str(uuid4())
    new_master.name += " Italic"
    new_master.axes['ital'] = 1
    new_masters.append(new_master)
    
# the copy of the master only contains metadata (like metrics
# and axis values), now copy contents from source master:
    addMissing = True  # Add missing glyphs from source to target
    font.copyGlyphs_sourceFontMasterID_targetFontMasterID_addMissing_(font, master.id, new_master.id, addMissing)

# Add the new masters to the font before setting italic angle
font.masters.extend(new_masters)

# Set the italic angle for the new masters
for new_master in new_masters:
    new_master.italicAngle = italic_angle

# 4) Duplicates all the instances and check their "Italic" checkbox in the "style linking"
for instance in list(font.instances):
    new_instance = instance.copy()
    new_instance.isItalic = True
    new_instance.linkStyle = new_instance.name
    new_instance.name += " Italic"
    new_instance.axes['ital'] = 1
    font.instances.append(new_instance)

# 5) Cursify all the glyphs in the Italic masters.
for master in new_masters:
    if master.axes['ital'] == 1:
        for glyph in font.glyphs:
            layer = glyph.layers[master.id]
            # Calculate half of the x-height
            x_height_half = master.xHeight / 2.0
            # Apply the italic transformation
            layer.slantX_origin_doCorrection_checkSelection_(italic_angle, x_height_half, True, True)


# Update the font metrics
font.metrics.updateMetrics()

# Update the font features
font.updateFeatures()


print("Easy Slants completed successfully.")

This depends on how you want to continue to work on your italic master.

I would suggest to apply the effect to only “root” glyphs where a “root” glyphs is not a composite.

  • root glyphs: A, a, ^, `, +, &, :
  • non-root/composite glyphs: Ä, ä, â, à

Generally, if a layer contains a path or non-automatically aligned component, it’s probably a root glyph.

Or, to be on the safe side, just apply it to a list of known glyphs that you want to automate and then run the script selectively as needed.

Yeah, that sounds like a good idea only applying it to the “root” glyphs. How would I be able to do that?

In step 5 of your script you process all glyphs:

for glyph in font.glyphs:
    # ...

There, check whether you want to process the glyph/layer and if not, skip the glyph. You can skip an iteration of the loop using the continue keyword:

for master in new_masters:
    if master.axes['ital'] == 1:
        for glyph in font.glyphs:
            layer = glyph.layers[master.id]
            # for example, only process if there are paths:
            if len(layer.paths) == 0:
                continue  # no paths: skip glyph
            # ... process layer with filter ...

Great! Thanks!

Two questions:

  1. Would you decompose brackets and so forth that are flipped components before or?

  1. It seem like new_instance.axes['ital'] = 1 and new_master.axes['ital'] = 1 doesn’t really set the axes coordinates?
  1. Maybe? I think I would also skip brackets in the script and then handle them individually afterwards. You could add exceptions for these glyphs in your script.
  2. Use internalAxesValues or externalAxesValues. See: Glyphs.app Python Scripting API Documentation — Glyphs.app Python Scripting API 3.0.4 documentation

Thanks for the help FlorianPircher and GeorgSeifert. I must say it’s pretty cool.
It can definitely still be improved. So if anyone is interested to continuing feel free to do so. If you want to see the final code for Easy Slants/Italic script — here it is:

# MenuTitle: Make Easy Slants
# -*- coding: utf-8 -*-
# Import the GlyphsApp module
from GlyphsApp import *

from uuid import uuid4

# Get the current font
font = Glyphs.font

# Define the italic angle
italic_angle = 9.5

# 1) Add an Axes called “Italic” in the font-info.
axis = GSAxis()
axis.name = "Italic"
axis.axisTag = "ital"
italic_axis_id = axis.id
font.axes.append(axis)

# 2) Set all the masters to "0" on the Italic axes.
for master in font.masters:
    master.internalAxesValues[italic_axis_id] = 0

# 3) Duplicate all the masters and set the new duplicated to "1" on the italic axis.
new_masters = []
for master in font.masters:
    new_master = master.copy()
    new_master.id = str(uuid4())
    new_master.name += " Italic"
    new_master.internalAxesValues[italic_axis_id] = 1
    new_masters.append(new_master)
    
    #the copy of the master only contains metadata (like metrics and axis values), now copy contents from source master:
    addMissing = True  # Add missing glyphs from source to target
    font.copyGlyphs_sourceFontMasterID_targetFontMasterID_addMissing_(font, master.id, new_master.id, addMissing)

# Add the new masters to the font before setting italic angle
font.masters.extend(new_masters)

# Set the italic angle for the new masters
for new_master in new_masters:
    new_master.italicAngle = italic_angle

# 4) Duplicates all the instances and check their "Italic" checkbox in the "style linking"
for instance in list(font.instances):
    new_instance = instance.copy()
    new_instance.isItalic = True
    new_instance.linkStyle = new_instance.name
    new_instance.name += " Italic"
    new_instance.internalAxesValues[italic_axis_id] = 1
    font.instances.append(new_instance)

# 5) Cursify all the glyphs containing paths in the Italic masters.
for master in new_masters:
    if master.internalAxesValues[italic_axis_id] == 1:
        for glyph in font.glyphs:
            layer = glyph.layers[master.id]
            # Only process if there are paths:
            if len(layer.paths) == 0:
                continue  # no paths: skip glyph
            
            # Calculate half of the x-height
            x_height_half = master.xHeight / 2.0
            # Apply the italic transformation
            layer.slantX_origin_doCorrection_checkSelection_(italic_angle, x_height_half, True, True)


# Update the font metrics and features
#font.metrics.updateMetrics()
font.updateFeatures()


print("Easy Slants completed successfully.")

Great! If you have a GitHub account, you can post the script there and I will add it to the ever-growing Glyphs Scripts Index where people can search for and learn from other’s code.

You can just flip them both vertically and horizontally.