## Interpolating colors

A simple DrawBot example showing basic interpolation maths at work.

``````# define two rgb colors
c1 = 0.5, 0.0, 0.3
c2 = 1.0, 0.6, 0.1

# total number of steps
steps = 14

# initial position
x, y = 0, 0

# calculate size for steps
w = width() / steps
h = height()

# iterate over the total amount of steps
for i in range(steps):

# calculate interpolation factor for this step
factor = i * 1.0 / (steps - 1)

# interpolate each rgb channel separately
r = c1[0] + factor * (c2[0] - c1[0])
g = c1[1] + factor * (c2[1] - c1[1])
b = c1[2] + factor * (c2[2] - c1[2])

# draw a rectangle with the interpolated color
fill(r, g, b)
stroke(r, g, b)
rect(x, y, w, h)

# increase x-position for the next step
x += w

``````

Modify color values and number of steps and see how the result changes.

## Interpolating position and size

Another visual example using DrawBot, this time interpolating position and size instead of RGB color channels.

``````# define position and size for two rectangles
x1, y1 = 98, 88
w1, h1 = 480, 492

x2, y2 = 912, 794
w2, h2 = 20, 126

# total amount of steps
steps = 22

# define blend mode and color
blendMode('multiply')
fill(0, 0.3, 1, 0.2)

# iterate over the total amount of steps
for i in range(steps):

# calculate interpolation factor for this step
factor = i * 1.0 / (steps - 1)

# interpolate each rectangle attribute separately
x = x1 + factor * (x2 - x1)
y = y1 + factor * (y2 - y1)
w = w1 + factor * (w2 - w1)
h = h1 + factor * (h2 - h1)

# draw a rectangle with the calculated variables
rect(x, y, w, h)

``````

## Checking interpolation compatibility

Before interpolating two glyphs, we need to make sure that they are compatible. We can do that in code, using a glyph’s `isCompatible` method. This function returns two values:

• The first value is a boolean indicating if the two glyphs are compatible.
• If the first value is `False`, the second will contain a report of the problems.
``````f = CurrentFont()
g = f['O']
print(g.isCompatible(f['o']))
print(g.isCompatible(f['n']))
``````
``````>>> (True, '')
>>> (False, '[Fatal] Contour 0 contains a different number of segments.\n[Fatal] Contour 1 contains a different number of segments.\n[Warning] The glyphs do not contain components with exactly the same base glyphs.')
``````

## Interpolating glyphs in the same font

This script generates a number of interpolation and extrapolation steps between two selected glyphs in the same font.

``````# settings
interpolationSteps = 5
extrapolateSteps = 2

# get the currentFont
f = CurrentFont()

if f is None:
# no font open
print("Oeps! There is not font open.")

else:
# get the selection
selection = f.selection

# check if the selection contains only two glyphs
if len(selection) != 2:
print("Incompatible selection: two compatible glyphs are required.")

else:
# get the master glyphs
source1 = f[selection[0]]
source2 = f[selection[1]]

# check if they are compatible
if not source1.isCompatible(source2)[0]:
# the glyphs are not compatible
print("Incompatible masters: Glyph %s and %s are not compatible." % (source1.name, source2.name))

else:
# loop over the amount of required interpolations
nameSteps = 0
for i in range(-extrapolateSteps, interpolationSteps + extrapolateSteps + 1, 1):
# create a new name
name = "interpolation.%03i" % nameSteps
nameSteps += 1
# create the glyph if does not exist
dest = f.newGlyph(name)
# get the interpolation factor (a value between 0.0 and 1.0)
factor = i / float(interpolationSteps)
# interpolate between the two masters with the factor
dest.interpolate(factor, source1, source2)

# done!
f.changed()
``````

## Interpolating glyphs into the current font

In this example, 3 fonts are open: the current font, where the glyphs will be interpolated, and two master fonts, named “Regular” and “Bold”. The master fonts are selected by their style names using `AllFonts().getFontsByStyleName()`.

``````# the font where the interpolated glyphs will be stored
f = CurrentFont()

# the two master fonts
f1 = AllFonts().getFontsByStyleName('Regular')[0]
f2 = AllFonts().getFontsByStyleName('Bold')[0]

# the interpolation factor
factor = 0.4

# a list of glyph names to be interpolated
glyphNames = ['A', 'B', 'C', 'a', 'b', 'c']

# iterate over the glyph names
for glyphName in glyphNames:

# if this glyph is not available in one of the masters, skip it
if not glyphName in f1:
print('%s not in %s, skipping…', (glyphName, f1))
continue
if not glyphName in f2:
print('%s not in %s, skipping…' % (glyphName, f1))
continue

# if the glyph does not exist in the destination font, create it
if not glyphName in f:
f.newGlyph(glyphName)

# interpolate glyph
print('interpolating %s…' % glyphName)
f[glyphName].interpolate(factor, f1[glyphName], f2[glyphName])
``````
``````>>> A not in RoboType Bold, skipping…
>>> interpolating B…
>>> interpolating C…
>>> interpolating a…
>>> interpolating b…
>>> interpolating c…
``````

## Interpolating fonts

This example will generate a new font by interpolating two existing fonts. We assume that both fonts are compatible.

``````# get fonts
font1 = OpenFont()
font2 = OpenFont()

# define interpolation factor
factor = 0.5

# make destination font
destination = NewFont()

# this interpolates the glyphs
destination.interpolate(factor, font1, font2)

# this interpolates the kerning
# comment this line out of you're just testing
destination.kerning.interpolate(font1.kerning, font2.kerning, factor)

# done!
destination.changed()
``````

## Batch interpolating fonts

This script generates a series of instances by interpolating two master fonts.

The names and interpolation values of the individual instances are defined in the code as a list of tuples.

``````import os
from vanilla.dialogs import getFolder

# get masters and destination folder
font1 = OpenFont()
font2 = OpenFont()
folder = getFolder("Select a folder to save the interpolations")[0]

# instance names and interpolation factors
instances = [
("Light", 0.25),
("Regular", 0.5),
("Bold", 0.75),
]

# generate instances
print('generating instances...\n')
for instance in instances:
styleName, factor = instance
print("\tgenerating %s (%s)..." % (styleName, factor))

# make a new font
dst = NewFont()

# interpolate the glyphs
dst.interpolate(factor, font1, font2)

# interpolate the kerning
# comment this line out of you're just testing
# dst.kerning.interpolate(font1.kerning, font2.kerning, value)

# set font name
dst.info.familyName = "MyFamily"
dst.info.styleName = styleName
dst.changed()

# save instance
fileName = '%s_%s.ufo' % (dst.info.familyName, dst.info.styleName)
ufoPath = os.path.join(folder, fileName)
print('\tsaving instances at %s...' % ufoPath)
dst.save(ufoPath)

# done with instance
dst.close()
print

print('...done.')
``````
``````>>> generating instances...
>>>
>>>    generating Light (0.25)...
>>>    saving instances at /myFolder/MyFamily_Light.ufo...
>>>
>>>    generating Regular (0.5)...
>>>    saving instances at /myFolder/MyFamily_Regular.ufo...
>>>
>>>    generating Bold (0.75)...
>>>    saving instances at /myFolder/MyFamily_Bold.ufo...
>>>
>>> ...done.
``````

## Condensomatic

A script to generate a Condensed from Regular and Bold. A Type]Media classic.

``````# a sample font containing Regular and Bold versions of a glyph
f = CurrentFont()

# Regular and Bold glyph names
regular = f['regular']
bold = f['bold']

# measure the stem widths for each weight
regularStem = 70
boldStem = 170

# condensing factor
condenseFactor = 0.2

# calculate scale factor from Regular and Bold stem widths
xFactor = float(regularStem) / (regularStem + condenseFactor * (boldStem - regularStem))

# create a new glyph for the result
g = f.newGlyph('condensed')
g.markColor = 1, 1, 0, 0.7

# interpolate weights
g.interpolate((condenseFactor, 0), regular, bold)

# scale glyph horizontally
g.scaleBy((xFactor, 1))

# calculate glyph margins
g.leftMargin = (regular.leftMargin + bold.leftMargin) * 0.5 * (1.0 - condenseFactor)
g.rightMargin = (regular.rightMargin + bold.rightMargin) * 0.5 * (1.0 - condenseFactor)

``````
Last edited on 27/03/2018