summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2022-09-27 03:09:36 +0300
committerRasmus Andersson <rasmus@notion.se>2022-09-27 03:09:36 +0300
commit3f174fcef6b614ee58716b7ec1b2744e137069ae (patch)
treeeb30e0f545b0dcfe7027c9fa576d798dddb3842b /misc
parent17875920ea7ee982da335f08b30a9037d9cdf252 (diff)
downloadinter-3f174fcef6b614ee58716b7ec1b2744e137069ae.tar.xz
Remove slnt/ital VF axis
This removes the slant/italic variable axis and breaks up the font in two: roman and italic. This change will allow diverging designs for italic (for example single-storey a). It also addresses the fact that most software, including web browsers, doesn't handle VFs with slnt or ital well.
Diffstat (limited to 'misc')
-rw-r--r--misc/dist/install-linux.txt4
-rw-r--r--misc/dist/install-mac.txt8
-rw-r--r--misc/dist/install-win.txt7
-rw-r--r--misc/dist/inter.css239
-rw-r--r--misc/makezip2.sh50
-rw-r--r--misc/tools/postprocess-designspace.py16
-rwxr-xr-xmisc/tools/postprocess-single-axis-vfs.py302
-rw-r--r--misc/tools/postprocess-vf.py24
-rwxr-xr-xmisc/tools/postprocess-vf2.py332
9 files changed, 436 insertions, 546 deletions
diff --git a/misc/dist/install-linux.txt b/misc/dist/install-linux.txt
index 7e83c95f8..d04e35b35 100644
--- a/misc/dist/install-linux.txt
+++ b/misc/dist/install-linux.txt
@@ -7,8 +7,8 @@ differently. These instructions are for the most common Linux distributions:
1. Create a folder called ".fonts" in your home directory.
Example: mkdir -p ~/.fonts
-2. Copy the otf files in the "Inter Desktop" folder into your .fonts directory
- Example: cp "Inter Desktop"/*.otf ~/.fonts/
+2. Copy the otf files in the "Desktop" folder into your .fonts directory
+ Example: cp "Desktop"/*.otf ~/.fonts/
You may have to restart apps and/or your window server session.
diff --git a/misc/dist/install-mac.txt b/misc/dist/install-mac.txt
index 36c0517d4..f68ea93c5 100644
--- a/misc/dist/install-mac.txt
+++ b/misc/dist/install-mac.txt
@@ -6,13 +6,13 @@ Using Font Book:
1. Open the "Font Book" application.
2. In the main menu, select File, then Add Fonts...
-3. Find the "Inter Desktop" folder, select the folder (or open the folder and
+3. Find the "Desktop" folder, select the folder (or open the folder and
select all the files inside the folder) and press the Open button.
Using Finder:
-1. Copy the "Inter Desktop" folder
-2. Press cmd-shift-G in Finder and go to: ~/Library/Fonts
+1. Copy the files in the "Desktop" folder
+2. Press cmd-shift-G in Finder and go to: ~/Library/Fonts
3. Delete any existing "Inter" files and folders
-4. Paste the "Inter Desktop" folder
+4. Paste the copied files
diff --git a/misc/dist/install-win.txt b/misc/dist/install-win.txt
index 85c22af00..b1c757a11 100644
--- a/misc/dist/install-win.txt
+++ b/misc/dist/install-win.txt
@@ -1,8 +1,8 @@
Installing on Windows 10:
-1. Copy the "Inter Desktop" folder in the zip file to your Desktop.
-2. Open the "Inter Desktop" folder on your Desktop.
+1. Copy the "Desktop" folder in the zip file to your Desktop.
+2. Open the "Desktop" folder on your Desktop.
4. Select all font files.
5. Right-click the selected files and choose "Install for all users".
@@ -21,5 +21,4 @@ of text. However, the hints for Inter are automatically generated and are
not always a good thing.
If you do prefer to use the version with hints, use the font files in the
-"Inter Hinted for Windows/Desktop" folder instead of "Inter Desktop".
-
+"Desktop with TrueType hints" folder instead of "Desktop".
diff --git a/misc/dist/inter.css b/misc/dist/inter.css
index f45001012..78359f9d7 100644
--- a/misc/dist/inter.css
+++ b/misc/dist/inter.css
@@ -1,200 +1,61 @@
+/* Variable fonts usage:
+:root { font-family: 'Inter', sans-serif; }
+@supports (font-variation-settings: normal) {
+ :root { font-family: 'InterVar', sans-serif; font-optical-sizing: auto; }
+} */
@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-Thin.woff2?v=3.19") format("woff2"),
- url("Inter-Thin.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"),
- url("Inter-ThinItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"),
- url("Inter-ExtraLight.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"),
- url("Inter-ExtraLightItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-Light.woff2?v=3.19") format("woff2"),
- url("Inter-Light.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"),
- url("Inter-LightItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 400;
- font-display: swap;
- src: url("Inter-Regular.woff2?v=3.19") format("woff2"),
- url("Inter-Regular.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url("Inter-Italic.woff2?v=3.19") format("woff2"),
- url("Inter-Italic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-Medium.woff2?v=3.19") format("woff2"),
- url("Inter-Medium.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"),
- url("Inter-MediumItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"),
- url("Inter-SemiBold.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"),
- url("Inter-SemiBoldItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url("Inter-Bold.woff2?v=3.19") format("woff2"),
- url("Inter-Bold.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"),
- url("Inter-BoldItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"),
- url("Inter-ExtraBold.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"),
- url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-Black.woff2?v=3.19") format("woff2"),
- url("Inter-Black.woff?v=3.19") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"),
- url("Inter-BlackItalic.woff?v=3.19") format("woff");
-}
-
-/* -------------------------------------------------------
-Variable font.
-Usage:
-
- html { font-family: 'Inter', sans-serif; }
- @supports (font-variation-settings: normal) {
- html { font-family: 'Inter var', sans-serif; }
- }
-*/
-@font-face {
- font-family: 'Inter var';
+ font-family: 'InterVar';
font-weight: 100 900;
font-display: swap;
font-style: normal;
font-named-instance: 'Regular';
- src: url("Inter-roman.var.woff2?v=3.19") format("woff2");
+ src: url("Inter.var.woff2?v=3.19") format("woff2-variations"),
+ url("Inter.var.woff2?v=3.19") format("woff2");
}
@font-face {
- font-family: 'Inter var';
+ font-family: 'InterVar';
font-weight: 100 900;
font-display: swap;
font-style: italic;
font-named-instance: 'Italic';
- src: url("Inter-italic.var.woff2?v=3.19") format("woff2");
-}
-
-
-/* --------------------------------------------------------------------------
-[EXPERIMENTAL] Multi-axis, single variable font.
-
-Slant axis is not yet widely supported (as of February 2019) and thus this
-multi-axis single variable font is opt-in rather than the default.
-
-When using this, you will probably need to set font-variation-settings
-explicitly, e.g.
-
- * { font-variation-settings: "slnt" 0deg }
- .italic { font-variation-settings: "slnt" 10deg }
-
-*/
-@font-face {
- font-family: 'Inter var experimental';
- font-weight: 100 900;
- font-display: swap;
- font-style: oblique 0deg 10deg;
- src: url("Inter.var.woff2?v=3.19") format("woff2");
-}
+ src: url("Inter-italic.var.woff2?v=3.19") format("woff2-variations"),
+ url("Inter-italic.var.woff2?v=3.19") format("woff2");
+}
+/* static fonts "Inter" */
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 100; font-display: swap; src: url("Inter-Thin.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 100; font-display: swap; src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 200; font-display: swap; src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 200; font-display: swap; src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 300; font-display: swap; src: url("Inter-Light.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 300; font-display: swap; src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url("Inter-Regular.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 400; font-display: swap; src: url("Inter-Italic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url("Inter-Medium.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 500; font-display: swap; src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 600; font-display: swap; src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url("Inter-Bold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 700; font-display: swap; src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap; src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 800; font-display: swap; src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: normal; font-weight: 900; font-display: swap; src: url("Inter-Black.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'Inter'; font-style: italic; font-weight: 900; font-display: swap; src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"); }
+/* static fonts "InterDisplay" */
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 100; font-display: swap; src: url("Inter-DisplayThin.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 100; font-display: swap; src: url("Inter-DisplayThinItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 200; font-display: swap; src: url("Inter-DisplayExtraLight.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 200; font-display: swap; src: url("Inter-DisplayExtraLightItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 300; font-display: swap; src: url("Inter-DisplayLight.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 300; font-display: swap; src: url("Inter-DisplayLightItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 400; font-display: swap; src: url("Inter-DisplayRegular.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 400; font-display: swap; src: url("Inter-DisplayItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 500; font-display: swap; src: url("Inter-DisplayMedium.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 500; font-display: swap; src: url("Inter-DisplayMediumItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 600; font-display: swap; src: url("Inter-DisplaySemiBold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 600; font-display: swap; src: url("Inter-DisplaySemiBoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 700; font-display: swap; src: url("Inter-DisplayBold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 700; font-display: swap; src: url("Inter-DisplayBoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 800; font-display: swap; src: url("Inter-DisplayExtraBold.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 800; font-display: swap; src: url("Inter-DisplayExtraBoldItalic.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: normal; font-weight: 900; font-display: swap; src: url("Inter-DisplayBlack.woff2?v=3.19") format("woff2"); }
+@font-face { font-family: 'InterDisplay'; font-style: italic; font-weight: 900; font-display: swap; src: url("Inter-DisplayBlackItalic.woff2?v=3.19") format("woff2"); }
diff --git a/misc/makezip2.sh b/misc/makezip2.sh
index 50180aeca..2dcfda03e 100644
--- a/misc/makezip2.sh
+++ b/misc/makezip2.sh
@@ -55,40 +55,30 @@ rm -f build/tmp/a.zip
# create directories
mkdir -p \
- "$ZIPDIR/Inter Desktop" \
- "$ZIPDIR/Inter Hinted for Windows/Desktop" \
- "$ZIPDIR/Inter Hinted for Windows/Web" \
- "$ZIPDIR/Inter Variable" \
- "$ZIPDIR/Inter Variable/Single axis" \
- "$ZIPDIR/Inter Web"
+ "$ZIPDIR/Desktop" \
+ "$ZIPDIR/Desktop with TrueType hints" \
+ "$ZIPDIR/Variable" \
+ "$ZIPDIR/Web"
# copy font files
# ----------------------------------------------------------------------------
-# Inter Desktop
-cp $FONTDIR/static/Inter-*.otf "$ZIPDIR/Inter Desktop/" &
-cp $FONTDIR/var/Inter-V.var.ttf "$ZIPDIR/Inter Desktop/Inter-V.ttf" &
-
-# Inter Hinted for Windows
-cp "misc/dist/about hinted fonts.txt" "$ZIPDIR/Inter Hinted for Windows/" &
-cp $FONTDIR/static-hinted/Inter-*.ttf "$ZIPDIR/Inter Hinted for Windows/Desktop/" &
-cp $FONTDIR/static-hinted/Inter-*.woff* "$ZIPDIR/Inter Hinted for Windows/Web/" &
-cp misc/dist/inter.css "$ZIPDIR/Inter Hinted for Windows/Web/" &
-
-# Inter Variable
-cp $FONTDIR/var/Inter.var.ttf \
- "$ZIPDIR/Inter Variable/Inter.ttf" &
-cp $FONTDIR/var/Inter-roman.var.ttf \
- "$ZIPDIR/Inter Variable/Single axis/Inter-roman.ttf" &
-cp $FONTDIR/var/Inter-italic.var.ttf \
- "$ZIPDIR/Inter Variable/Single axis/Inter-italic.ttf" &
-
-# Inter Web
-cp $FONTDIR/static/Inter-*.woff* "$ZIPDIR/Inter Web/" &
-cp $FONTDIR/var/Inter.var.woff2 "$ZIPDIR/Inter Web/" &
-cp $FONTDIR/var/Inter-roman.var.woff2 "$ZIPDIR/Inter Web/" &
-cp $FONTDIR/var/Inter-italic.var.woff2 "$ZIPDIR/Inter Web/" &
-cp misc/dist/inter.css "$ZIPDIR/Inter Web/" &
+# Desktop
+cp $FONTDIR/static/Inter-*.otf "$ZIPDIR/Desktop/" &
+
+# Hinted for Windows
+cp "misc/dist/about hinted fonts.txt" "$ZIPDIR/Desktop with TrueType hints/" &
+cp $FONTDIR/static-hinted/Inter-*.ttf "$ZIPDIR/Desktop with TrueType hints/" &
+
+# Variable ("Inter" and "Inter V")
+cp $FONTDIR/var/Inter*.var.ttf "$ZIPDIR/Variable/" &
+
+# Web
+cp $FONTDIR/static/Inter-*.woff* "$ZIPDIR/Web/" &
+cp $FONTDIR/var/Inter.var.woff2 "$ZIPDIR/Web/" &
+cp $FONTDIR/var/Inter-italic.var.woff2 "$ZIPDIR/Web/" &
+cp misc/dist/inter.css "$ZIPDIR/Web/" &
+
# ----------------------------------------------------------------------------
# copy misc stuff
diff --git a/misc/tools/postprocess-designspace.py b/misc/tools/postprocess-designspace.py
index 9d5203e69..51ad5ab85 100644
--- a/misc/tools/postprocess-designspace.py
+++ b/misc/tools/postprocess-designspace.py
@@ -24,14 +24,23 @@ def update_version(ufo):
ufo.info.openTypeNameUniqueID = "%s-%s:%d:%s" % (psFamily, psStyle, now.year, buildtag)
ufo.info.openTypeHeadCreated = now.strftime("%Y/%m/%d %H:%M:%S")
-def fix_opsz_maximum(designspace):
+def fix_opsz_range(designspace):
+ # TODO: find extremes by looking at the source
for a in designspace.axes:
if a.tag == "opsz":
- # TODO: find maximum by looking at the source
+ a.minimum = 14
a.maximum = 32
break
return designspace
+def fix_wght_range(designspace):
+ for a in designspace.axes:
+ if a.tag == "wght":
+ a.minimum = 100
+ a.maximum = 900
+ break
+ return designspace
+
def should_decompose_glyph(g):
# A trivial glyph is one that does not use components or where component transformation
# does not include mirroring (i.e. "flipped").
@@ -83,7 +92,8 @@ def update_sources(designspace):
def main(argv):
designspace_file = argv[1]
designspace = DesignSpaceDocument.fromfile(designspace_file)
- designspace = fix_opsz_maximum(designspace)
+ designspace = fix_opsz_range(designspace)
+ designspace = fix_wght_range(designspace)
designspace = update_sources(designspace)
designspace.write(designspace_file)
diff --git a/misc/tools/postprocess-single-axis-vfs.py b/misc/tools/postprocess-single-axis-vfs.py
deleted file mode 100755
index 4e34a2557..000000000
--- a/misc/tools/postprocess-single-axis-vfs.py
+++ /dev/null
@@ -1,302 +0,0 @@
-#
-# from gftools
-# https://github.com/googlefonts/gftools/blob/
-# deebf9eb018856ffc7f0d939aea18606dc432c5a/bin/gftools-fix-vf-meta.py
-#
-"""
-Fontmake can only generate a single variable font. It cannot generate a
-family of variable fonts, that are related to one another.
-
-This script will update the nametables and STAT tables so a family
-which has more than one variable font will work correctly in desktop
-applications.
-
-It will also work on single font VF families by creating a better STAT
-table.
-
-TODO make script work on VFs which have multiple axises. We'll need to
-change the axis array format to v4 (we're using v1),
-https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4
-
-Atm, the script will work well for single axis fonts and families which
-have a single vf for Roman and another for Italic/Condensed, both using the wght
-axis (covers 95% of GF cases).
-"""
-import os, sys
-from argparse import ArgumentParser
-from fontTools.ttLib import TTFont, newTable
-from fontTools.ttLib.tables import otTables
-
-if sys.version_info.major == 3:
- unicode = str
-
-OS_2_WEIGHT_CLASS = {
- 'Thin': 100,
- 'ExtraLight': 200,
- 'Light': 300,
- 'Regular': 400,
- '': 400,
- 'Medium': 500,
- 'SemiBold': 600,
- 'Bold': 700,
- 'ExtraBold': 800,
- 'Black': 900,
-}
-
-
-def _parse_styles(stylename):
- bold, italic = False, False
- if 'Italic' in stylename:
- italic = True
- bold = False
- if 'Bold' == stylename or 'Bold Italic' == stylename:
- bold = True
- return bold, italic
-
-
-def set_fsselection(style, fsselection,):
- bold, italic = _parse_styles(style)
-
- mask = 0b1100001
- fsselection = (fsselection | mask) ^ mask
-
- if bold:
- fsselection |= 0b100000
- else:
- fsselection |= 0b1000000
- if italic:
- # unset Reg bit
- fsselection = (fsselection | 0b1000000) ^ 0b1000000
- fsselection |= 0b1
- return fsselection
-
-
-def set_mac_style(stylename, macstyle):
- bold, italic = _parse_styles(stylename)
-
- mask = ~0b11
- bold_bit = 0b1 if bold else 0b0
- italic_bit = 0b10 if italic else 0b0
-
- macstyle = (macstyle | mask) ^ mask
- macstyle |= (bold_bit + italic_bit)
- return macstyle
-
-
-def set_weight_class(stylename):
- weight = stylename.replace('Italic', '').replace(' ', '')
- return OS_2_WEIGHT_CLASS[weight]
-
-
-def fonts_are_same_family(ttfonts):
- """Check fonts have the same preferred family name or family name"""
- family_names = []
- for ttfont in ttfonts:
- pref_family_name = ttfont['name'].getName(16, 3, 1, 1033)
- family_name = ttfont['name'].getName(1, 3, 1, 1033)
- name = pref_family_name if pref_family_name else family_name
- family_names.append(name.toUnicode())
- if len(set(family_names)) != 1:
- return False
- return True
-
-
-def fix_bits(ttfont):
- """Set fsSelection, macStyle and usWeightClass to correct values.
-
- The values must be derived from the default style. By default, the
- Regular instance's values are used"""
- dflt_style = _get_vf_default_style(ttfont)
- ttfont['OS/2'].fsSelection = set_fsselection(
- dflt_style, ttfont['OS/2'].fsSelection
- )
- ttfont['OS/2'].usWeightClass = set_weight_class(dflt_style)
- ttfont['head'].macStyle = set_mac_style(
- dflt_style, ttfont['head'].macStyle
- )
-
-
-def create_stat_table(ttfont):
- """Atm, Fontmake is only able to produce a basic stat table. Because of
- this, we'll create a STAT using the font's fvar table."""
- stat = newTable('STAT')
- stat.table = otTables.STAT()
- stat.table.Version = 0x00010001
-
- # # Build DesignAxisRecords from fvar
- stat.table.DesignAxisRecord = otTables.AxisRecordArray()
- stat.table.DesignAxisRecord.Axis = []
-
- stat_axises = stat.table.DesignAxisRecord.Axis
-
- # TODO (M Foley) add support for fonts which have multiple
- # axises e.g Barlow
- if len(ttfont['fvar'].axes) > 1:
- raise Exception('VFs with more than one axis are currently '
- 'not supported.')
-
- for idx, axis in enumerate(ttfont['fvar'].axes):
- append_stat_axis(stat, axis.axisTag, axis.axisNameID)
-
- # Build AxisValueArrays for each namedInstance from fvar namedInstances
- stat.table.AxisValueArray = otTables.AxisValueArray()
- stat.table.AxisValueArray.AxisValue = []
-
- for idx, instance in enumerate(ttfont['fvar'].instances):
- append_stat_record(stat, 0, list(instance.coordinates.values())[0], instance.subfamilyNameID)
-
- # Set ElidedFallbackNameID
- stat.table.ElidedFallbackNameID = 2
- ttfont['STAT'] = stat
-
-
-def _get_vf_types(ttfonts):
- styles = []
- for ttfont in ttfonts:
- styles.append(_get_vf_type(ttfont))
- return styles
-
-
-def _get_vf_type(ttfont):
- if ttfont['head'].macStyle & 0b10:
- return 'Italic'
- return 'Roman'
-
-
-def _get_vf_default_style(ttfont):
- """Return the name record string of the default style"""
- default_fvar_val = ttfont['fvar'].axes[0].defaultValue
-
- name_id = None
- for inst in ttfont['fvar'].instances:
- if inst.coordinates['wght'] == default_fvar_val:
- name_id = inst.subfamilyNameID
- return ttfont['name'].getName(name_id, 3, 1, 1033).toUnicode()
-
-
-def add_other_vf_styles_to_nametable(ttfont, text_records):
- """Each nametable in a font must reference every font in the family.
- Since fontmake doesn't append the other families to the nametable,
- we'll do this ourselves. Skip this step if these records already
- exist."""
- found = set()
- for name in ttfont['name'].names[:-len(text_records)-1:-1]:
- found.add(name.toUnicode())
- leftover = set(text_records) - found
-
- if leftover:
- nameid = ttfont['name'].names[-1].nameID + 1
- for record in leftover:
- ttfont['name'].setName(unicode(record), nameid, 3, 1, 1033)
- nameid += 1
-
-
-def get_custom_name_record(ttfont, text):
- """Return a name record by text. Record ID must be greater than 255"""
- for record in ttfont['name'].names[::-1]:
- if record.nameID > 255:
- rec_text = record.toUnicode()
- if rec_text == text:
- return record
- return None
-
-
-def append_stat_axis(stat, tag, namerecord_id):
- """Add a STAT axis if the tag does not exist already."""
- has_tags = []
- axises = stat.table.DesignAxisRecord.Axis
- for axis in axises:
- has_tags.append(axis.AxisTag)
-
- if tag in has_tags:
- raise Exception('{} has already been declared in the STAT table')
-
- axis_record = otTables.AxisRecord()
- axis_record.AxisTag = tag
- axis_record.AxisNameID = namerecord_id
- axis_record.AxisOrdering = len(axises)
- axises.append(axis_record)
-
-
-def append_stat_record(stat, axis_index, value, namerecord_id, linked_value=None):
- records = stat.table.AxisValueArray.AxisValue
- axis_record = otTables.AxisValue()
- axis_record.Format = 1
- axis_record.ValueNameID = namerecord_id
- axis_record.Value = value
- axis_record.AxisIndex = axis_index
-
- axis_record.Flags = 0
- if linked_value:
- axis_record.Format = 3
- axis_record.LinkedValue = linked_value
- records.append(axis_record)
-
-
-def get_stat_axis_index(ttfont, axis_name):
- axises = ttfont['STAT'].table.DesignAxisRecord.Axis
- available_axises = [a.AxisTag for a in axises]
- for idx, axis in enumerate(axises):
- if axis.AxisTag == axis_name:
- return idx
- raise Exception('{} is not a valid axis. Font has [{}] axises'.format(
- axis_name, available_axises)
- )
-
-
-def set_stat_for_font_in_family(ttfont, family_styles):
- """Based on examples from:
- https://docs.microsoft.com/en-us/typography/opentype/spec/stat"""
- font_type = _get_vf_type(ttfont)
- # See example 5
- if font_type == 'Roman' and 'Italic' in family_styles:
- name_record = get_custom_name_record(ttfont, 'Italic')
- append_stat_axis(ttfont['STAT'], 'ital', name_record.nameID)
-
- name_record = get_custom_name_record(ttfont, 'Roman')
- axis_idx = get_stat_axis_index(ttfont, 'ital')
- append_stat_record(ttfont['STAT'], axis_idx, 0, name_record.nameID, linked_value=1.0)
-
- elif font_type == 'Italic' and 'Roman' in family_styles:
- name_record = get_custom_name_record(ttfont, 'Italic')
- append_stat_axis(ttfont['STAT'], 'ital', name_record.nameID)
-
- name_record = get_custom_name_record(ttfont, 'Italic')
- axis_idx = get_stat_axis_index(ttfont, 'ital')
- append_stat_record(ttfont['STAT'], axis_idx, 1.0, name_record.nameID)
-
-
-def harmonize_vf_families(ttfonts):
- """Make sure the fonts which are part of a vf family reference each other
- in both the nametable and STAT table. For examples see:
- https://docs.microsoft.com/en-us/typography/opentype/spec/stat
-
- """
- family_styles = _get_vf_types(ttfonts)
- for ttfont in ttfonts:
- add_other_vf_styles_to_nametable(ttfont, family_styles)
- set_stat_for_font_in_family(ttfont, family_styles)
-
-
-def main():
- parser = ArgumentParser()
- parser.add_argument('fonts', nargs='+',
- help='All fonts within a font family must be included')
- args = parser.parse_args()
- font_paths = args.fonts
- ttfonts = [TTFont(p) for p in font_paths]
- if not fonts_are_same_family(ttfonts):
- raise Exception('Fonts have different family_names: [{}]'.format(
- ', '.join(map(os.path.basename, font_paths))
- ))
-
- for ttfont in ttfonts:
- fix_bits(ttfont)
- create_stat_table(ttfont)
- harmonize_vf_families(ttfonts)
-
- for path, ttfont in zip(font_paths, ttfonts):
- ttfont.save(path)
-
-if __name__ == '__main__':
- main()
diff --git a/misc/tools/postprocess-vf.py b/misc/tools/postprocess-vf.py
index e0fb66fc7..7e2bf785c 100644
--- a/misc/tools/postprocess-vf.py
+++ b/misc/tools/postprocess-vf.py
@@ -28,7 +28,7 @@ FAMILY_RELATED_IDS = set([
whitespace_re = re.compile(r'\s+')
-def removeWhitespace(s):
+def remove_whitespace(s):
return whitespace_re.sub("", s)
@@ -57,19 +57,19 @@ def get_family_name(font):
def fix_fullname(font):
fullName = get_family_name(font)
- fullNamePs = removeWhitespace(fullName)
+ fullNamePs = remove_whitespace(fullName)
set_full_name(font, fullName, fullNamePs)
return fullName
-def clear_subfamily_name(font):
- nameTable = font["name"]
- rmrecs = []
- for rec in nameTable.names:
- if rec.nameID == SUBFAMILY_NAME or rec.nameID == TYPO_SUBFAMILY_NAME:
- rmrecs.append(rec)
- for rec in rmrecs:
- nameTable.removeNames(rec.nameID, rec.platformID, rec.platEncID, rec.langID)
+# def clear_subfamily_name(font):
+# nameTable = font["name"]
+# rmrecs = []
+# for rec in nameTable.names:
+# if rec.nameID == SUBFAMILY_NAME or rec.nameID == TYPO_SUBFAMILY_NAME:
+# rmrecs.append(rec)
+# for rec in rmrecs:
+# nameTable.removeNames(rec.nameID, rec.platformID, rec.platEncID, rec.langID)
def fix_unique_id(font, fullName):
@@ -80,7 +80,7 @@ def fix_unique_id(font, fullName):
if rec.nameID == TRUETYPE_UNIQUE_ID:
if newId == '':
oldId = rec.toUnicode()
- newId = removeWhitespace(fullName)
+ newId = remove_whitespace(fullName)
p = oldId.find(':')
if p > -1:
newId += oldId[p:]
@@ -105,7 +105,7 @@ def main():
fullName = fix_fullname(font)
fix_unique_id(font, fullName)
- clear_subfamily_name(font)
+ #clear_subfamily_name(font)
font.save(outfile)
font.close()
diff --git a/misc/tools/postprocess-vf2.py b/misc/tools/postprocess-vf2.py
new file mode 100755
index 000000000..4eb29f981
--- /dev/null
+++ b/misc/tools/postprocess-vf2.py
@@ -0,0 +1,332 @@
+#!/usr/bin/env python3
+#
+# from gftools
+# https://github.com/googlefonts/gftools/blob/
+# 8b53f595a08d1b3f86f86eb97e07b15b1f52f671/bin/gftools-fix-vf-meta.py
+#
+"""
+Add a STAT table to a weight only variable font.
+
+This script can also add STAT tables to a variable font family which
+consists of two fonts, one for Roman, the other for Italic.
+Both of these fonts must also only contain a weight axis.
+
+For variable fonts with multiple axes, write a python script which
+uses fontTools.otlLib.builder.buildStatTable e.g
+https://github.com/googlefonts/literata/blob/main/sources/gen_stat.py
+
+The generated STAT tables use format 2 Axis Values. These are needed in
+order for Indesign to work.
+
+Special mention to Thomas Linard for reviewing the output of this script.
+
+
+Usage:
+
+Single family:
+gftools fix-vf-meta FontFamily[wght].ttf
+
+Roman + Italic family:
+gftools fix-vf-meta FontFamily[wght].ttf FontFamily-Italic[wght].ttf
+"""
+from fontTools.otlLib.builder import buildStatTable
+from fontTools.ttLib import TTFont
+# from gftools.utils import font_is_italic
+import argparse, re
+
+
+whitespace_re = re.compile(r'\s+')
+
+
+def remove_whitespace(s):
+ return whitespace_re.sub("", s)
+
+
+def font_is_italic(ttfont):
+ if ttfont['head'].macStyle & 0b10:
+ return True
+ return False
+ # # Check if the font has the word "Italic" in its stylename
+ # stylename = ttfont["name"].getName(2, 3, 1, 0x409).toUnicode()
+ # return True if "Italic" in stylename else False
+
+
+def font_has_mac_names(ttfont):
+ for record in ttfont['name'].names:
+ if record.platformID == 1:
+ return True
+ return False
+
+
+def build_stat(roman_font, italic_font=None):
+ roman_wght_axis = dict(
+ tag="wght",
+ name="Weight",
+ values=build_wght_axis_values(roman_font),
+ )
+ roman_opsz_axis = dict(
+ tag="opsz",
+ name="Optical size",
+ values=build_opsz_axis_values(roman_font),
+ )
+ roman_axes = [roman_wght_axis, roman_opsz_axis]
+
+ if italic_font:
+ # We need to create a new Italic axis in the Roman font
+ roman_axes.append(dict(
+ tag="ital",
+ name="Italic",
+ values=[
+ dict(
+ name="Roman",
+ flags=2,
+ value=0.0,
+ linkedValue=1.0,
+ )
+ ]
+ ))
+ italic_wght_axis = dict(
+ tag="wght",
+ name="Weight",
+ values=build_wght_axis_values(italic_font),
+ )
+ italic_opsz_axis = dict(
+ tag="opsz",
+ name="Optical size",
+ values=build_opsz_axis_values(italic_font),
+ )
+ italic_ital_axis = dict(
+ tag="ital",
+ name="Italic",
+ values=[
+ dict(
+ name="Italic",
+ value=1.0,
+ )
+ ]
+ )
+ italic_axes = [italic_wght_axis, italic_opsz_axis, italic_ital_axis]
+ #print("buildStatTable(italic_font)", italic_axes)
+ buildStatTable(italic_font, italic_axes)
+ #print("buildStatTable(roman_font)", roman_axes)
+ buildStatTable(roman_font, roman_axes)
+
+
+def build_stat_v2(roman_font, italic_font=None):
+ roman_wght_axis = dict(
+ tag="wght",
+ name="Weight",
+ )
+ roman_opsz_axis = dict(
+ tag="opsz",
+ name="Optical size",
+ )
+ roman_axes = [roman_wght_axis, roman_opsz_axis]
+ locations = [
+ dict(name='Regular', location=dict(wght=400, opsz=14)),
+ dict(name='Regular Display', location=dict(wght=400, opsz=32)),
+ dict(name='Bold', location=dict(wght=700, opsz=14)),
+ dict(name='Bold Display', location=dict(wght=700, opsz=32)),
+ ]
+ buildStatTable(roman_font, roman_axes, locations)
+
+
+def build_opsz_axis_values(ttfont):
+ nametable = ttfont['name']
+ instances = ttfont['fvar'].instances
+
+ val_min = 0.0
+ val_max = 0.0
+ for instance in instances:
+ opsz_val = instance.coordinates["opsz"]
+ if val_min == 0.0 or opsz_val < val_min:
+ val_min = opsz_val
+ if val_max == 0.0 or opsz_val > val_max:
+ val_max = opsz_val
+
+ return [
+ {
+ "name": "Regular",
+ "value": val_min,
+ "linkedValue": val_max,
+ "flags": 2,
+ },
+ {
+ "name": "Display",
+ "value": val_max,
+ },
+ ]
+
+ # results = []
+ # for instance in instances:
+ # opsz_val = instance.coordinates["opsz"]
+ # name = nametable.getName(instance.subfamilyNameID, 3, 1, 1033).toUnicode()
+ # name = name.replace("Italic", "").strip()
+ # if name == "":
+ # name = "Regular"
+ # inst = {
+ # "name": name,
+ # "value": opsz_val,
+ # }
+ # if int(opsz_val) == val_min:
+ # inst["flags"] = 0
+ # inst["linkedValue"] = val_max
+ # else:
+ # inst["linkedValue"] = val_min
+ # results.append(inst)
+
+ # return results
+
+
+def build_wght_axis_values(ttfont):
+ results = []
+ nametable = ttfont['name']
+ instances = ttfont['fvar'].instances
+ has_bold = any([True for i in instances if i.coordinates['wght'] == 700])
+ for instance in instances:
+ wght_val = instance.coordinates["wght"]
+ name = nametable.getName(instance.subfamilyNameID, 3, 1, 1033).toUnicode()
+ #print(nametable.getName(instance.postscriptNameID, 3, 1, 1033).toUnicode())
+ name = name.replace("Italic", "").strip()
+ if name == "":
+ name = "Regular"
+ inst = {
+ "name": name,
+ "nominalValue": wght_val,
+ }
+ if inst["nominalValue"] == 400:
+ inst["flags"] = 0x2
+ results.append(inst)
+
+ # Dynamically generate rangeMinValues and rangeMaxValues
+ entries = [results[0]["nominalValue"]] + \
+ [i["nominalValue"] for i in results] + \
+ [results[-1]["nominalValue"]]
+ for i, entry in enumerate(results):
+ entry["rangeMinValue"] = (entries[i] + entries[i+1]) / 2
+ entry["rangeMaxValue"] = (entries[i+1] + entries[i+2]) / 2
+
+ # Format 2 doesn't support linkedValues so we have to append another
+ # Axis Value (format 3) for Reg which does support linkedValues
+ if has_bold:
+ inst = {
+ "name": "Regular",
+ "value": 400,
+ "flags": 0x2,
+ "linkedValue": 700
+ }
+ results.append(inst)
+ return results
+
+
+def update_nametable(ttfont):
+ """
+ - Add nameID 25
+ - Update fvar instance names and add fvar instance postscript names
+ """
+ is_italic = font_is_italic(ttfont)
+ has_mac_names = font_has_mac_names(ttfont)
+
+ # Add nameID 25
+ # https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids
+ vf_ps_name = _add_nameid_25(ttfont, is_italic, has_mac_names)
+
+ nametable = ttfont['name']
+ instances = ttfont["fvar"].instances
+
+ print("%d instances of %s:" % (len(instances), "Italic" if is_italic else "Roman"))
+
+ # find opsz max
+ opsz_val_max = 0.0
+ for instance in instances:
+ opsz_val = instance.coordinates["opsz"]
+ if opsz_val_max == 0.0 or opsz_val > opsz_val_max:
+ opsz_val_max = opsz_val
+
+ # Update fvar instances
+ i = 0
+ for inst in instances:
+ inst_name = nametable.getName(inst.subfamilyNameID, 3, 1, 1033).toUnicode()
+ print("instance %2d" % i, inst_name)
+ i += 1
+
+ # Update instance subfamilyNameID
+ if is_italic:
+ inst_name = inst_name.strip()
+ inst_name = inst_name.replace("Regular Italic", "Italic")
+ inst_name = inst_name.replace("Italic", "").strip()
+ inst_name = inst_name + " Italic"
+ ttfont['name'].setName(inst_name, inst.subfamilyNameID, 3, 1, 0x409)
+ if has_mac_names:
+ ttfont['name'].setName(inst_name, inst.subfamilyNameID, 1, 0, 0)
+
+ # Add instance psName
+ ps_name = vf_ps_name + remove_whitespace(inst_name)
+ ps_name_id = ttfont['name'].addName(ps_name)
+ inst.postscriptNameID = ps_name_id
+
+
+def _add_nameid_25(ttfont, is_italic, has_mac_names):
+ name = ttfont['name'].getName(16, 3, 1, 1033) or \
+ ttfont['name'].getName(1, 3, 1, 1033).toUnicode()
+ # if is_italic:
+ # name = f"{name}Italic"
+ # else:
+ # name = f"{name}Roman"
+ # ttfont['name'].setName(name, 25, 3, 1, 1033)
+ if is_italic:
+ name = f"{name}Italic"
+ ttfont['name'].setName(name, 25, 3, 1, 1033)
+ if has_mac_names:
+ ttfont['name'].setName(name, 25, 1, 0, 0)
+ return name
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=__doc__
+ )
+ parser.add_argument("fonts", nargs="+", help=(
+ "Paths to font files. Fonts must be part of the same family."
+ )
+ )
+ args = parser.parse_args()
+ paths = args.fonts
+
+ # This monstrosity exists so we don't break the v1 api.
+ italic_font = None
+ if len(paths) > 2:
+ raise Exception(
+ "Can only add STAT tables to a max of two fonts. "
+ "Run gftools fix-vf-meta --help for usage instructions"
+ )
+ elif len(paths) == 2:
+ if "Italic" in paths[0]:
+ tmp = paths[0]
+ paths[0] = paths[1]
+ paths[1] = tmp
+ elif "Italic" not in paths[1]:
+ raise Exception("No Italic font found!")
+ roman_font = TTFont(paths[0])
+ italic_font = TTFont(paths[1])
+ else:
+ roman_font = TTFont(paths[0])
+
+ update_nametable(roman_font)
+ if italic_font:
+ update_nametable(italic_font)
+
+ build_stat(roman_font, italic_font)
+
+ roman_font.save(paths[0] + "-fixed.ttf")
+ if italic_font:
+ italic_font.save(paths[1] + "-fixed.ttf")
+
+ # roman_font.save(paths[0])
+ # if italic_font:
+ # italic_font.save(paths[1])
+
+
+if __name__ == "__main__":
+ main()