Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/Nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ jobs:
runs-on: windows-latest
permissions:
contents: write
packages: write
steps:
- name: Update draft on GitHub Releases
id: release_drafter
Expand Down
18 changes: 15 additions & 3 deletions CSharpMath.Core.Example/BackEnd/JsonMathTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class JsonMathTable : FontMathTable<TFont, TGlyph> {
/// typically loaded from a .json file.</summary>
private readonly JToken _mathTable;
private readonly JObject _constantsDictionary;
private readonly JObject _assemblyTable;
private readonly JObject _vAssemblyTable, _hAssemblyTable;
private readonly JObject _italicTable;
public TestFontMeasurer FontMeasurer { get; }
public TestGlyphNameProvider GlyphNameProvider { get; }
Expand All @@ -41,7 +41,8 @@ JObject GetTable(string name) =>
GlyphBoundsProvider = glyphBoundsProvider;
_mathTable = mathTable;
_constantsDictionary = GetTable("constants");
_assemblyTable = GetTable("v_assembly");
_vAssemblyTable = GetTable("v_assembly");
_hAssemblyTable = GetTable("h_assembly");
_italicTable = GetTable("italic");
}
// different from _ConstantFromTable in that the _ConstantFromTable requires
Expand Down Expand Up @@ -137,7 +138,18 @@ public override float RadicalExtraAscender(TFont font) =>
private const string _extenderKey = "extender";
private const string _glyphKey = "glyph";
public override IEnumerable<GlyphPart<TGlyph>>? GetVerticalGlyphAssembly(TGlyph rawGlyph, TFont font) =>
_assemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
_vAssemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
? parts.Select(partInfo =>
new GlyphPart<TGlyph>(
GlyphNameProvider.GetGlyph(partInfo[_glyphKey]!.Value<string>()!),
FontUnitsToPt(font, partInfo[_advanceKey]!.Value<int>()),
FontUnitsToPt(font, partInfo[_startConnectorKey]!.Value<int>()),
FontUnitsToPt(font, partInfo[_endConnectorKey]!.Value<int>()),
partInfo[_extenderKey]!.Value<bool>()))
// Should have been defined, but let's return null
: null;
public override IEnumerable<GlyphPart<TGlyph>>? GetHorizontalGlyphAssembly(TGlyph rawGlyph, TFont font) =>
_hAssemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
? parts.Select(partInfo =>
new GlyphPart<TGlyph>(
GlyphNameProvider.GetGlyph(partInfo[_glyphKey]!.Value<string>()!),
Expand Down
7 changes: 4 additions & 3 deletions CSharpMath.Core.Example/CSharpMath.Core.Example.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
<StartupObject>CSharpMath.Core.Checker</StartupObject>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\CSharpMath\CSharpMath.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<EmbeddedResource Include="Resources\latinmodern-math.json" />
<ProjectReference Include="..\CSharpMath\CSharpMath.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<EmbeddedResource Include="Resources\latinmodern-math.json" />
<None Include="Resources\MathTableExport.py" />
</ItemGroup>
</Project>
216 changes: 216 additions & 0 deletions CSharpMath.Core.Example/Resources/MathTableExport.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Based on https://github.com/kostub/iosMath/blob/master/fonts/math_table_to_plist.py
# Added: get_h_assembly (version 1.3 -> 1.4)

import sys
import json
from fontTools.ttLib import TTFont

def process_font(font_file, out_file):
font = TTFont(font_file)
math_table = font['MATH'].table
constants = get_constants(math_table)
italic_c = get_italic_correction(math_table)
v_variants = get_v_variants(math_table)
h_variants = get_h_variants(math_table)
v_assembly = get_v_assembly(math_table)
h_assembly = get_h_assembly(math_table)
accents = get_accent_attachments(math_table)
pl = {
"version" : "1.4",
"constants": constants,
"v_variants" : v_variants,
"h_variants" : h_variants,
"italic" : italic_c,
"accents" : accents,
"v_assembly" : v_assembly,
"h_assembly" : h_assembly }
ofile = open(out_file, 'w')
json.dump(pl, ofile)
ofile.close()

def get_constants(math_table):
constants = math_table.MathConstants
if constants is None:
raise 'Cannot find MathConstants in MATH table'

int_consts = [ 'ScriptPercentScaleDown',
'ScriptScriptPercentScaleDown',
'DelimitedSubFormulaMinHeight',
'DisplayOperatorMinHeight',
'RadicalDegreeBottomRaisePercent']
consts = { c : getattr(constants, c) for c in int_consts }

record_consts = [ 'MathLeading',
'AxisHeight',
'AccentBaseHeight',
'FlattenedAccentBaseHeight',
'SubscriptShiftDown',
'SubscriptTopMax',
'SubscriptBaselineDropMin',
'SuperscriptShiftUp',
'SuperscriptShiftUpCramped',
'SuperscriptBottomMin',
'SuperscriptBaselineDropMax',
'SubSuperscriptGapMin',
'SuperscriptBottomMaxWithSubscript',
'SpaceAfterScript',
'UpperLimitGapMin',
'UpperLimitBaselineRiseMin',
'LowerLimitGapMin',
'LowerLimitBaselineDropMin',
'StackTopShiftUp',
'StackTopDisplayStyleShiftUp',
'StackBottomShiftDown',
'StackBottomDisplayStyleShiftDown',
'StackGapMin',
'StackDisplayStyleGapMin',
'StretchStackTopShiftUp',
'StretchStackBottomShiftDown',
'StretchStackGapAboveMin',
'StretchStackGapBelowMin',
'FractionNumeratorShiftUp',
'FractionNumeratorDisplayStyleShiftUp',
'FractionDenominatorShiftDown',
'FractionDenominatorDisplayStyleShiftDown',
'FractionNumeratorGapMin',
'FractionNumDisplayStyleGapMin',
'FractionRuleThickness',
'FractionDenominatorGapMin',
'FractionDenomDisplayStyleGapMin',
'SkewedFractionHorizontalGap',
'SkewedFractionVerticalGap',
'OverbarVerticalGap',
'OverbarRuleThickness',
'OverbarExtraAscender',
'UnderbarVerticalGap',
'UnderbarRuleThickness',
'UnderbarExtraDescender',
'RadicalVerticalGap',
'RadicalDisplayStyleVerticalGap',
'RadicalRuleThickness',
'RadicalExtraAscender',
'RadicalKernBeforeDegree',
'RadicalKernAfterDegree',
]
consts_2 = { c : getattr(constants, c).Value for c in record_consts }
consts.update(consts_2)

variants = math_table.MathVariants
consts['MinConnectorOverlap'] = variants.MinConnectorOverlap
return consts

def get_italic_correction(math_table):
glyph_info = math_table.MathGlyphInfo
if glyph_info is None:
raise "Cannot find MathGlyphInfo in MATH table."
italic = glyph_info.MathItalicsCorrectionInfo
if italic is None:
raise "Cannot find Italic Correction in GlyphInfo"

glyphs = italic.Coverage.glyphs
count = italic.ItalicsCorrectionCount
records = italic.ItalicsCorrection
italic_dict = {}
for i in range(count):
name = glyphs[i]
record = records[i]
if record.DeviceTable is not None:
raise "Don't know how to process device table for italic correction."
italic_dict[name] = record.Value
return italic_dict

def get_accent_attachments(math_table):
glyph_info = math_table.MathGlyphInfo
if glyph_info is None:
raise "Cannot find MathGlyphInfo in MATH table."
attach = glyph_info.MathTopAccentAttachment
if attach is None:
raise "Cannot find Top Accent Attachment in GlyphInfo"

glyphs = attach.TopAccentCoverage.glyphs
count = attach.TopAccentAttachmentCount
records = attach.TopAccentAttachment
attach_dict = {}
for i in range(count):
name = glyphs[i]
record = records[i]
if record.DeviceTable is not None:
raise "Don't know how to process device table for accent attachment."
attach_dict[name] = record.Value
return attach_dict

def get_v_variants(math_table):
variants = math_table.MathVariants
vglyphs = variants.VertGlyphCoverage.glyphs
vconstruction = variants.VertGlyphConstruction
count = variants.VertGlyphCount
variant_dict = {}
for i in range(count):
name = vglyphs[i]
record = vconstruction[i]
glyph_variants = [x.VariantGlyph for x in
record.MathGlyphVariantRecord]
variant_dict[name] = glyph_variants
return variant_dict

def get_h_variants(math_table):
variants = math_table.MathVariants
hglyphs = variants.HorizGlyphCoverage.glyphs
hconstruction = variants.HorizGlyphConstruction
count = variants.HorizGlyphCount
variant_dict = {}
for i in range(count):
name = hglyphs[i]
record = hconstruction[i]
glyph_variants = [x.VariantGlyph for x in
record.MathGlyphVariantRecord]
variant_dict[name] = glyph_variants
return variant_dict

def get_v_assembly(math_table):
variants = math_table.MathVariants
vglyphs = variants.VertGlyphCoverage.glyphs
vconstruction = variants.VertGlyphConstruction
count = variants.VertGlyphCount
assembly_dict = {}
for i in range(count):
name = vglyphs[i]
record = vconstruction[i]
assembly = record.GlyphAssembly
if assembly is not None:
# There is an assembly for this glyph
italic = assembly.ItalicsCorrection.Value
parts = [part_dict(part) for part in assembly.PartRecords]
assembly_dict[name] = {
"italic" : assembly.ItalicsCorrection.Value,
"parts" : parts }
return assembly_dict

def get_h_assembly(math_table):
variants = math_table.MathVariants
hglyphs = variants.HorizGlyphCoverage.glyphs
hconstruction = variants.HorizGlyphConstruction
count = variants.HorizGlyphCount
assembly_dict = {}
for i in range(count):
name = hglyphs[i]
record = hconstruction[i]
assembly = record.GlyphAssembly
if assembly is not None:
# There is an assembly for this glyph
italic = assembly.ItalicsCorrection.Value
parts = [part_dict(part) for part in assembly.PartRecords]
assembly_dict[name] = {
"italic" : assembly.ItalicsCorrection.Value,
"parts" : parts }
return assembly_dict

def part_dict(part):
return {
"glyph": part.glyph,
"startConnector" : part.StartConnectorLength,
"endConnector" : part.EndConnectorLength,
"advance" : part.FullAdvance,
"extender" : (part.PartFlags == 1) }

process_font('../../CSharpMath.Rendering/Reference Fonts/latinmodern-math.otf', 'latinmodern-math.json')
Loading
Loading