TTC files are TrueType Collection files that contain the data needed to represent multiple font styles and font weights; this is a collection. On the other hand, TTF files are TrueType Font files, that contains the data required to work with only one font style or one font weight (for example: Regular, Bold or Light).
There are a lot of free websites you can use to extract the individual styles and weights from a .ttc file and create .ttf files. But why not do this with Xojo, just for fun … or because I need it! Keep reading and I will show you how.
Extracting the available styles and weights from TTC files requires parsing its data to find the data chunks required to compose the TTF. That is what we are going to do. Start by creating a new Desktop project (you can adapt it later for any supported Xojo targets like Web or Mobile).
Building the TTC to TTF Converter
All the work is going to be done via a method; but because it will be dealing with font files, it would be a good idea to start by creating our own
FontUtilities module. So, add a new module to the project and name it “FontUtilities” in the Inspector Panel.
FontUtilities selected in the Navigator, add a new method to it using the following signature:
- Method Name: ExtractTTFStylesFromTTC
- Parameters: inputFile As FolderItem, outputFolder As FolderItem
- Scope: Public
And add the following code into the associated Code Editor:
#Pragma DisableBackgroundTasks #Pragma DisableBoundsChecking #Pragma StackOverflowChecking False If inputFile = Nil Or Not inputFile.Exists Then Return If outputFolder = Nil Or Not outputFolder.IsFolder Or Not outputFolder.IsWriteable Then Return Var mb As MemoryBlock Var rb As BinaryStream = BinaryStream.Open(inputFile) mb = rb.Read(inputFile.Length) mb.LittleEndian = False rb.Close If mb <> Nil Then Var OutputBuffers() As MemoryBlock // Let's make sure this is a .ttc file by checking the first four bytes of the header If mb.StringValue(0, 4) <> "ttcf" Then Return // offset for the total of faces/styles in the ttc file Var totalFaces As Integer = mb.UInt32Value(8) Var tableHeaderOffset As Integer Var tableCount As UInt16 Var headerLength, tLength, tableLength, totalLength, currentOffset As Integer Var outputBuffer As MemoryBlock For n As Integer = 0 To totalFaces - 1 // 0x0c is the first possition of the tableHeader offsets tableHeaderOffset = mb.UInt32Value(12 + (n * 4)) // offset to the table count from the current table header offset tableCount = mb.UInt16Value(tableHeaderOffset+4) headerLength = 12 + tableCount * 16 tableLength = 0 For j As Integer = 0 To tableCount - 1 tLength = mb.UInt32Value(tableHeaderOffset+12+12+(j*16)) tableLength = tableLength + Bitwise.BitAnd(tLength + 3, Bitwise.OnesComplement(3)) // next value multiple of four Next totalLength = headerLength + tableLength outputBuffer = New MemoryBlock(totalLength) outputBuffer.LittleEndian = False //Copy table to the buffer for the new file outputBuffer.StringValue(0,headerLength - 1) = mb.StringValue(tableHeaderOffset, headerLength - 1) currentOffset = headerLength Var tOffset, tOtherLength As Integer For j As Integer = 0 To tableCount - 1 tOffset = mb.UInt32Value(tableHeaderOffset + 12 + 8 + (j * 16)) tOtherLength = mb.UInt32Value(tableHeaderOffset + 12 + 12 + (j * 16)) outputBuffer.UInt32Value(12 + 8 + (j * 16)) = currentOffset // Copy data to the buffer for the new file outputBuffer.StringValue(currentOffset, tOtherLength - 1) = mb.StringValue(tOffset, tOtherLength - 1) outputBuffer.UInt32Value(currentOffset) = mb.UInt32Value(tOffset) currentOffset = currentOffset + Bitwise.BitAnd(tOtherLength + 3, Bitwise.OnesComplement(3)) // next value multiple of four Next outputBuffers.Add(outputBuffer) Next // Let's create the .ttf files in the output folder Var max As Integer = outputBuffers.Count - 1 Var outputFile As FolderItem For n As Integer = 0 To max outputFile = outputFolder.Child(inputFile.Name.NthField(".", 1) + " " + n.ToString + ".ttf") Var ob As BinaryStream = BinaryStream.Create(outputFile) ob.Write(outputBuffers(n)) ob.Close Next End If
Testing the TTC to TTF Converter
Now, let’s create a minimal user interface in order to test it. Select the
Window1 window in the Navigator in order to bring up the Layout Editor. Next, drag a
DesktopButton from the Library and drop it inside the window area in the Layout Editor. Use the alignment guides to help you to leave enough room between the button and the window margins.
Double click the button in the Layout Editor to open the Add Event Handler dialog box. The
Pressed Event Handler should be selected already, so simply confirm it clicking on the “OK” button.
Pressed Event Handler has been added under
Button1 in the Navigator and with its associated Code Editor visible in the main area, type the following lines of code:
Var inputFontFile As FolderItem = FolderItem.ShowOpenFileDialog(".ttc") Var outputFolder As FolderItem = FolderItem.ShowSelectFolderDialog FontUtilities.ExtractTTFStylesFromTTC(inputFontFile, outputFolder)
The first line of code will ask the user to select the “.ttc” font file to process, and the second line will ask for the destination folder where the output (the converted .ttf font files) will be stored. Finally, the third line of code is the one calling our
ExtractTFFStylesFromTTC method passing along both the file to process and the output folder.
That’s all! Click on the Run button in the main toolbar of the Xojo IDE. Once the app is running, click on the button to select any “.ttc” file you want to process. Next, the app will ask you to select the output folder and you will be able to see the extracted files inside the selected output folder.
Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at Goto 10 and on Twitter @lefebvre.