-
Notifications
You must be signed in to change notification settings - Fork 312
Open
Labels
Description
Adding support for True Type Collection file parsing in SystemFontFinder could help support more font (e.g. the MS Gothic font is contained in a .ttc file, not .ttf. As a result it is currently not loaded).
Adding support should be straightforward. Basic implementation below (written with help of AI assistant). Initial tests are promising.
public static IReadOnlyList<TrueTypeFont> ParseTtcFonts(byte[] input, int maxFonts = int.MaxValue)
{
var bytes = input;
if (bytes.Length < 12 || bytes[0] != 0x74 || bytes[1] != 0x74 || bytes[2] != 0x63 || bytes[3] != 0x66)
{
// Not TTC
throw new InvalidOperationException("Input data is not a valid TrueType Collection (TTC) file.");
}
// TTC detected: ttcf at offset 0
uint version = BinaryPrimitives.ReadUInt32BigEndian(bytes.AsSpan(4, 4));
if (version != 0x00010000 && version != 0x00020000)
{
throw new InvalidOperationException($"Unsupported TTC version: {version:X8}");
}
uint numFonts = BinaryPrimitives.ReadUInt32BigEndian(bytes.AsSpan(8, 4));
if (numFonts == 0)
{
throw new InvalidOperationException("TTC contains no fonts.");
}
var offsets = new List<uint>((int)Math.Min(numFonts, maxFonts));
for (int i = 0; i < numFonts && offsets.Count < maxFonts; i++)
{
uint offset = BinaryPrimitives.ReadUInt32BigEndian(bytes.AsSpan(12 + i * 4, 4));
if (offset > 0)
{
offsets.Add(offset);
}
}
var subInput = new TrueTypeDataBytes(bytes);
var fonts = new List<TrueTypeFont>(offsets.Count);
foreach (uint offset in offsets)
{
if (offset >= bytes.Length)
{
continue; // Invalid offset, skip
}
try
{
subInput.Seek(offset); // TTF starts at offset
var font = TrueTypeFontParser.Parse(subInput);
fonts.Add(font);
}
catch (Exception ex)
{
// Log or handle parse error for this sub-font
Console.WriteLine($"Failed to parse TTC font at offset {offset}: {ex.Message}");
}
}
return fonts.AsReadOnly();
}Reactions are currently unavailable