Creating Fonts with Inkscape and FontForge | Part#5
<Part#4> - Table of Contents - <Part#6>
Part#5 - Initials & Finals
In this tutorial, we create a simple font with three letters, two of which have final and initial forms. There is also a single ligature.
Rules:
- Ligatures are added first
- Then, all initials/finals are replaced with the adequate glyph
-
Create a font project named “Font#5”
-
Create the glyphs 2. Open Inkscape and draw these glyphs using bezier curves of stroke width = 40px.
SetFile|Document Properties|pagewidth/height=1200px, and add a rectangular grid withSpacingX=50. -
Import the glyphs
- The ascent/descent are both at 600px.
- Import the glyphs, don't forget to convert the bezier curves to path with
Path|Stroke to Path. screen
Referer to tutorial 4 to add the extra glyphsa.init, b.init, a.fina, b.fina, b_c - Set both bearings of the glyphs to
-20and create the glyph for space.
-
The feature file
-
Create a text file named "Font#5.fea" and type in the following code:
<code begin>
languagesystem DFLT dflt;
languagesystem latn dflt;feature liga {
lookup NoCaps {
sub A by a;
sub B by b;
sub C by c;
} NoCaps;lookup Ligatures {
sub b c by b_c;
} Ligatures;} liga;
<code end> -
All this does is map Upper case letters to Lower case and apply the ligature. Don't import the feature file yet.
Because the lookup NoCaps requires them, we need to create the glyphs A,B,C or we will get an error upon importing the file.
-
What we want next is to substitute initials letters. Consider the following glyph stream
a|b|a|b. Our lookup Initial should outputa.init|b|a|b.
A second lookup Final will take this steam as it's input and outputa.init|b|a|b.fina.
Here is the code for it:<code begin>
languagesystem DFLT dflt;
languagesystem latn dflt;feature liga {
lookup NoCaps {
sub A by a;
sub B by b;
sub C by c;
} NoCaps;lookup Ligatures {
sub b c by b_c;
} Ligatures;lookup Initals {
@Glyphs = [a.init b.init a b c b_c];
ignore sub @Glyphs [a b]';
sub [a b]' by [a.init b.init];
} Initals;lookup Finals {
@Glyphs = [a b c b_c];
ignore sub [a b]' @Glyphs;
sub [a b]' by [a.fina b.fina];
} Finals;} liga;
<code end>This is a trick using the
ignorekeyword. It is explained here in the Opentype Cookbook. Basically, this rule ignores any letter that has another letter before it.
The only times the second rule will match is when there are no other letters before it. In other words, the second rule will only succeed if it is an initial letter.In the same way, inside Final, we ignore any letter that has another letter behind it. The second rule will only match letters that have no other letters behind them. In other words, it will match the finals.
PS: When I write "letters" I really mean "glyphs", when writing each lookup we need to consider which glyphs have already been replaced by the lookups before it. For instance the class
@Allneed to contain not only[a, b, c ...]but also the ligatures that may have been added to the stream at this point such as[a.init, b.init, b_c]. We need to add the initials to it because theignorerule is looking backwards from it's current position in the stream. -
We could've written Initial and Final before Ligatures: Here's what this would look like. You can try to import both. The code to achieve the same effect is not the same as you can see (refer to the paragraph above for why that is). One is slightly more complex than the other.
<code begin>
languagesystem DFLT dflt;
languagesystem latn dflt;feature liga {
lookup NoCaps {
sub A by a;
sub B by b;
sub C by c;
} NoCaps;lookup Initals {
@Glyphs = [a.init b.init a b c];
ignore sub @Glyphs [a b]';
sub [a b]' by [a.init b.init];
} Initals;lookup Finals {
@Glyphs = [a b c];
ignore sub [a b]' @Glyphs;
sub [a b]' by [a.fina b.fina];
} Finals;lookup Ligatures {
sub [b.init b] c by b_c;
} Ligatures;} liga;
<code end> -
And here's what this would look like if "c" had a final and initial form.
<code begin>
languagesystem DFLT dflt;
languagesystem latn dflt;feature liga {
lookup NoCaps {
sub A by a;
sub B by b;
sub C by c;
} NoCaps;lookup Initals {
@Glyphs = [a.init b.init c.init a b c];
ignore sub @Glyphs [a b c]';
sub [a b c]' by [a.init b.init c.init];
} Initals;lookup Finals {
@Glyphs = [a b c];
ignore sub [a b c]' @Glyphs;
sub [a b c]' by [a.fina b.fina c.fina];
} Finals;lookup Ligatures {
sub [b.init b] [c c.fina] by b_c;
} Ligatures;} liga;
<code end> -
Remember that the first rule of this script is "Ligatures are added first". Therefore, if we add the finals/initial first, we need to be able to ligate them afterwards. This is why you need to think about the order in which you write your lookups, and define the rules of your script precisely, in order to make your code as simple as possible. This is especially important as these kinds of things compound with each lookup that you add, and you have to account for them for the rest of the feature file. If we had lots of ligatures, you can see how this would be harder to read and more error prone.
-
You should've imported one of the two feature files. Simply generate the font: Result.
-
Posted Mar 2, 2018, 6:02 PM UTC · edited