Los archivos TTC son archivos de colección de fuentes TrueType que incluyen los datos necesarios para representar múltiples estilos y pesos de fuentes. Por otra parte, los archivos TFF son archivos de fuente TrueType que contienen los datos requeridos para trabajar con tan sólo un estilo o peso de fuente (por ejemplo: Regular, Bold o Light).
Hay multitud de sitios web gratuitos que puedes utilizar para extraer los estilos y pesos de una fuente .ttc como archivos individuales en formato .ttf. Pero, ¿por qué no hacer esto mismo con Xojo? Ya sea por diversión… o porque lo necesites. Continúa leyendo y te mostraré cómo.
Extraer los estilos y pesos disponibles en los archivos TTC requiere de procesar sus datos para encontrar los fragmentos requeridos para componer la fuente TTF. Esto es lo que vamos a hacer. Comienza creando un nuevo proyecto de escritorio con Xojo (puedes adaptarlo posteriormente para que funcione con Web o Mobile).
Índice
Crear el conversor de TTC a TTF
Todo el trabajo de extracción se va a hacer con un método, pero ya que estamos tratando con archivos de fuente, sería buena idea crear un módulo FontUtilities. Por tanto, añade un nuevo módulo al proyecto y nómbralo como “FontUtilities” en el Panel Inspector.
A continuación, con FontUtilities seleccionado en el Navegador, añádele un nuevo método utilizando la siguiente signatura:
Method Name: ExtractTTFStylesFromTTC
Parameters: inputFile As FolderItem, outputFolder As FolderItem
Scope: Public
Y escribe el siguiente código en el Editor de Código asociado:
#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
Probando el Conversor de TTC a TTF
Ahora vamos a crear una interfaz de usuario mínima para probar nuestro conversor. Selecciona la ventana Window1 en el Navegador para que se muestre en el Editor de Diseño. A continuación, arrastra un DesktopButton desde la Librería y suéltalo dentro del área de la ventana en el Editor de Diseño. Utiliza las guías de alineación como ayuda sobre dónde situar el control, de modo que deje el suficiente espacio entre el botón y los márgenes de la ventana.
Haz doble clic en el botón en el Editor de Diseño para abrir el cuadro de diálogo de Add Event Handler. Debería de aparecer seleccionado por omisión el Manejador de Evento Pressed, de modo que sólo has de confirmarlo haciendo clic en el botón “OK”.
Se habrá añadido el Manejador de Evento Pressed bajo Button1 en el Navegador de Xojo, y ahora estará visible su Editor de Código asociado en el área principal del IDE. Escribe las siguientes líneas de código:
Var inputFontFile As FolderItem = FolderItem.ShowOpenFileDialog(".ttc")
Var outputFolder As FolderItem = FolderItem.ShowSelectFolderDialog
FontUtilities.ExtractTTFStylesFromTTC(inputFontFile, outputFolder)
La primera línea de código indicará al usuario que seleccione un archivo de fuente “.ttc” para procesarlo, y la segunda línea le solicitará que seleccione la carpeta de destino donde se guardarán los archivos procesados (convertidos a archivos de fuente .ttf). Por último, la tercera línea de código es la encargada de llamar el método ExtractTFFStylesFromTTC pasando tanto el archivo a procesar como la carpeta de salida.
¡Eso es todo! Haz clic en el botón Run en la barra de herramientas principal del IDE de Xojo. Una vez que la app esté en funcionamiento, haz clic en el botón para seleccionar el archivo “ttc” a procesar. A continuación, la app te pedirá que selecciones la carpeta de salida y verás entonces todos los archivos creados dentro de ella en un abrir y cerrar de ojos.
Clases interesantes
En este ejemplo con Xojo estamos utilizando algunas clases interesantes que no habíamos visto hasta ahora.
Por ejemplo, MemoryBlock es la clase que nos permite crear y trabajar con regiones de memoria. Ofrece métodos que nos permiten trabajar con los datos almacenados en dicha región como si fueran cadenas de texto, números enteros, de coma flotante, etc; incluso acceder a una posición concreta y acceder al valor almacenado como si fuera un byte.
También podemos crear nuevas instancias de MemoryBlock a partir de una cadena de texto o stream de datos. Esto es lo que hacemos por ejemplo cuando leemos de un BinaryStream.
Precisamente BinaryStream es otra de las clases interesantes, ya que nos permite crear una instancia de flujo de datos binarios (no procesados) a partir de una instancia FolderItem. Por tanto te recomiendo que eches un vistazo en profundidad sobre cómo trabajan las clases MemoryBlock, FolderItem y BinaryStream en la documentación de Xojo.