Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[builder] allow slicing of VF with continuous ital axis #627

Open
7 of 11 tasks
RosaWagner opened this issue Nov 11, 2022 · 4 comments
Open
7 of 11 tasks

[builder] allow slicing of VF with continuous ital axis #627

RosaWagner opened this issue Nov 11, 2022 · 4 comments
Labels
builder Issues related to the gftools-builder

Comments

@RosaWagner
Copy link
Contributor

RosaWagner commented Nov 11, 2022

I made a 3 test cases using varLib.instancer (ITAL=-12, SLANT=-12, ITAL=1) which I link here.
Mona_tests.zip

To make it short, I think we should make builder slicing the VF when we have ITAL=1 because it would be the easiest one to fix. This is my checklist to see if Italic style linking is correct, what is un-check should be patched/fixed by gftools:

Name

  • ID25 appends Italic
  • ID2,17,etc have Italic

Style linking bits

  • post (italic angle is not 0)
  • hhea (caret slope is not 1)
  • head (macstyle is Italic)
  • OS/2 (fsSelection is Italic)

Design space

  • only italic instances
  • no slant/ital slider
  • ital axis in stat
  • ital value is 1
  • change reference to nameID2 and 17 in STAT

Explanation about the last check:
The entries in the STAT table that matches ID2 and 17, are referred as such. So when the name tables are updated for the resulting Italic fonts, we end up with the wrong value names, like this:

STAT.ttx.zip

Particularly these pieces in the weight axis:

        <Flags value="0"/>
        <ValueNameID value="17"/>  <!-- ExtraLight Italic -->
        <Value value="200.0"/>
      </AxisValue>

I should be ExtraLight instead. Value should not be nameID 17, it should be name ID 261 'ExtraLight', but it is missing from the name table.

        <AxisIndex value="1"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="2"/>  <!-- Italic -->
        <Value value="400.0"/>
        <LinkedValue value="700.0"/>
      </AxisValue>

It should be Regular. Value should not be nameID 2, it should be nameID 263 'Regular', but it is missing from the name table.

@RosaWagner
Copy link
Contributor Author

This is the little patch to fix these issues for now:

import glob
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables._n_a_m_e import NameRecord

if __name__ == "__main__":

    for font_path in glob.glob("../fonts/variable/*Italic*.ttf"):
        with open(font_path, "rb") as f:
            print("Fix italic style linking in {}".format(font_path))
            ttFont = TTFont(f)
            ttFont["post"].italicAngle = -12
            ttFont["hhea"].caretSlopeRise = 1000
            ttFont["hhea"].caretSlopeRun = 213
            ttFont["name"].setName("MonaSansItalic", 25, 3, 1, 0x409)
            ttFont["name"].setName("ExtraLight", 261, 3, 1, 0x409)
            ttFont["name"].setName("Regular", 263, 3, 1, 0x409)
            ttFont["name"].setName("ExtraLight", 261, 1, 0, 0)
            ttFont["name"].setName("Regular", 263, 1, 0, 0)
            for axisvalue in ttFont["STAT"].table.AxisValueArray.AxisValue:
                if axisvalue.ValueNameID == 2:
                    axisvalue.ValueNameID = 263
                if axisvalue.ValueNameID == 17:
                    axisvalue.ValueNameID = 261
            ttFont.save(font_path)

Feel free to edit it to make it better.

@simoncozens simoncozens added the builder Issues related to the gftools-builder label Nov 28, 2022
@RosaWagner
Copy link
Contributor Author

This is @yanone script:

import sys
import math
from fontTools.ttLib import TTFont

font = TTFont(sys.argv[-1])
name = font["name"]
stat = font["STAT"]


def set_name(nameID, string):
    for record in name.names:
        if record.nameID == nameID:
            name.setName(
                string,
                record.nameID,
                record.platformID,
                record.platEncID,
                record.langID,
            )


def get_name(nameID):
    for record in name.names:
        if record.nameID == nameID:
            return record.toUnicode()


def get_axis(tag):
    for i, axis in enumerate(font["STAT"].table.DesignAxisRecord.Axis):
        if axis.AxisTag == tag:
            return i, axis


def get_axis_value(axisTag, name):
    for axisValue in stat.table.AxisValueArray.AxisValue:
        if (
            axisValue.AxisIndex == get_axis(axisTag)[0]
            and get_name(axisValue.ValueNameID) == name
        ):
            return axisValue


set_name(2, "Italic")
name.setName("Regular", 262, 3, 1, 1033)
name.setName("Regular", 262, 1, 0, 0)

for nameID in (3, 4, 6):
    set_name(nameID, get_name(nameID).replace("Regular", "Italic"))


get_axis_value("wght", "Italic").ValueNameID = 262

# Italic angle
post = font["post"]
post.italicAngle = -12
font["post"] = post

# Caret slope
hhea = font["hhea"]
hhea.caretSlopeRise = font["head"].unitsPerEm
hhea.caretSlopeRun = round(
    math.atan(math.radians(abs(post.italicAngle))) * font["head"].unitsPerEm
)
font["hhea"] = hhea

font["head"].macStyle |= 1 << 1

# Unset
for value in [0, 5, 6]:
    font["OS/2"].fsSelection &= ~(1 << value)
# Set Italic
font["OS/2"].fsSelection |= 1 << 0


font["STAT"] = stat
font.save(sys.argv[-1])

@yanone
Copy link
Contributor

yanone commented Jan 9, 2023

FWIW, here's an updated script that should work with almost any Italic VF. (The italicAngle is font-specific, tho).

import sys
import math
from fontTools.ttLib import TTFont

font = TTFont(sys.argv[-2])


def set_name(nameID, string):
    for record in font["name"].names:
        if record.nameID == nameID:
            old_string = record.toUnicode()
            if string != old_string:
                font["name"].setName(
                    string,
                    record.nameID,
                    record.platformID,
                    record.platEncID,
                    record.langID,
                )
                print(
                    f"Set ID {nameID} ({record.platformID},{record.platEncID},{record.langID}) to '{string}'"
                )


def get_name(nameID):
    for record in font["name"].names:
        if record.nameID == nameID:
            return record.toUnicode()


def get_axis(tag):
    for i, axis in enumerate(font["STAT"].table.DesignAxisRecord.Axis):
        if axis.AxisTag == tag:
            return i, axis


def get_axis_value(axisTag, name):
    for axisValue in font["STAT"].table.AxisValueArray.AxisValue:
        if (
            axisValue.AxisIndex == get_axis(axisTag)[0]
            and get_name(axisValue.ValueNameID) == name
        ):
            return axisValue


# Italic angle
font["post"].italicAngle = -11

# macStyle bit
font["head"].macStyle |= 1 << 1

# fsSelection
# Unset first
for value in [0, 5, 6]:
    font["OS/2"].fsSelection &= ~(1 << value)
# Then set Italic
font["OS/2"].fsSelection |= 1 << 0

# Set subfamilyname
set_name(2, "Italic")

# Change ID 4 (PostScript Name)
if get_name(4).endswith("Regular"):
    set_name(4, get_name(4).replace("Regular", "Italic"))
else:
    set_name(4, get_name(4) + " Italic")

# Change ID 6 (PostScript Name)
old_postscript_name = get_name(6)
if get_name(6).endswith("Regular"):
    set_name(6, get_name(6).replace("Regular", "Italic"))
else:
    set_name(6, get_name(6) + "Italic")

# Change ID 3 (Unique Font ID)
set_name(3, get_name(3).replace(old_postscript_name, get_name(6)))

# Change ID 17
if get_name(17).endswith("Regular"):
    set_name(17, get_name(17).replace("Regular", "Italic"))
else:
    set_name(17, get_name(17) + " Italic")

# Change ID 25
set_name(25, get_name(25) + "Italic")

# Adjust fvar instance names to include "Italic"
for instance in font["fvar"].instances:
    if not get_name(instance.subfamilyNameID).endswith("Italic"):
        new_name = get_name(instance.subfamilyNameID) + " Italic"
        if new_name == "Regular Italic":
            new_name = "Italic"
        set_name(instance.subfamilyNameID, new_name)


# Caret slope
font["hhea"].caretSlopeRise = font["head"].unitsPerEm
font["hhea"].caretSlopeRun = round(
    math.tan(math.radians(abs(font["post"].italicAngle))) * font["head"].unitsPerEm
)

font.save(sys.argv[-1])

@yanone
Copy link
Contributor

yanone commented Jan 16, 2023

Update: In the above code snipped, the italic angle got abs()'d, so it assumes right-leaning fonts. This is correct:

font["hhea"].caretSlopeRun = round(math.tan(math.radians(-font["post"].italicAngle)) * font["head"].unitsPerEm)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
builder Issues related to the gftools-builder
Projects
None yet
Development

No branches or pull requests

3 participants