Trabajar con la tabla 'nombre' | C++
La tabla de fuentes TrueType ’nombre’ es el almacenamiento de cadenas de texto relacionadas con esa fuente. Estas cadenas se pueden escribir en diferentes idiomas y pueden representar varias entidades, como nombres de fuentes, apellidos, nombres de diseñadores, información de licencia, avisos de derechos de autor, etc. En resumen, las líneas que se encuentran en la tabla ’nombre’ describen los metadatos de la fuente.
Esquema de la tabla ’nombre'.
The detailed specification for ’name’ table is accessible in * Microsoft* and Apple documentations.
Hay 2 formatos para una tabla de ’nombre’ con los números 0 y 1 respectivamente. En términos de la tabla ’nombre’, estos números de formato se denominan versión, por lo que el formato 0 se designa como versión 0 y el formato 1, como versión 1.
El formato 1 se diferencia del formato 0 en la identificación del idioma. Cualquier entrada en la tabla ’nombre’ tiene un identificador de idioma, que se utiliza para detectar el idioma de esa cadena. Y la diferencia entre el formato 0 y el formato 1 está en cómo se interpretan estos identificadores de idioma.
Los identificadores de idioma para el formato 0 tienen una interpretación específica de la plataforma, pero los identificadores de idioma para el formato 1 están asociados con cadenas de etiquetas de idioma, que identifican los idiomas independientemente de la plataforma.
Para mayor precisión, el formato 1 permite mantener identificadores de idioma de ambos tipos: identificadores con interpretación específica de la plataforma e identificadores asociados con cadenas de etiquetas de idioma (es decir, independientes de una plataforma).
La biblioteca Aspose.Font admite el formato 0 de la tabla ’nombre’. Está prevista la compatibilidad con el formato 1 para futuras versiones.
Independientemente del formato que tenga la tabla ’nombre’, cualquier entrada en esta tabla se basa en un componente particular: la estructura NameRecord.
Los cuatro parámetros principales de esta estructura son:
- identificador de plataforma(platformID),
- identificador específico de la plataforma (platformSpecificID),
- identificador de nombre (nameID),
- e identificador de idioma (languageID).
Los parámetros platformID
, platformSpecificID
y languageID
se utilizan para configurar el idioma de la cadena de manera específica de la plataforma. Los valores de los parámetros platformSpecificID
y languageID
solo importan en el contexto del parámetro platformID.
Por ejemplo, “platformSpecificID” igual a 0 define la escritura romana para la plataforma Mac y, al mismo tiempo, “platformSpecificID” define la escritura romana para la plataforma Windows. De manera similar, el valor de “languageID” solo importa en el contexto del parámetro platformID utilizado.
Por ejemplo, languageID
que define inglés EE. UU. es igual a 0 para platformID = 1 (Mac) y 0x0409 para platformID
= 3 (Windows).
Las exclusiones solo son languageID
para el formato de tabla de nombres 1, asociado con una cadena de etiqueta de idioma, que identifica los idiomas independientemente de la plataforma.
El parámetro “nameID” es un número que identifica una categoría de cadena lógica, como nombre de fuente, apellido y otros. Hay un conjunto predefinido de identificadores de nombres, que es el mismo para todas las plataformas e idiomas.
Así, cada entrada de la tabla ’nombre’ se puede dividir condicionalmente en 3 partes:
- categoría de cadena lógica,
- lenguaje de cadenas,
- la cuerda misma.
El parámetro nameID
está relacionado con la primera parte, los parámetros platformID
, platformSpecificID
y languageID
están relacionados con la segunda parte.
¿Cómo trabajar con registros de la tabla ’nombre’ usando Aspose.Font?
El soporte para la tabla ’nombre’ lo proporciona la clase TtfNameTable. Además, consideramos la funcionalidad de este objeto.
Primero, describamos las enumeraciones necesarias para trabajar con la funcionalidad de la clase TtfNameTable.
- Las enumeraciones NameID y PlatformId están relacionadas con los parámetros descritos anteriormente como nameID y platformID.
- Las enumeraciones UnicodePlatformSpecificId, MacPlatformSpecificId están relacionadas con el parámetro platformSpecificID.
Como se mencionó anteriormente, “los valores de los parámetros platformSpecificID e languageID sólo importan en el contexto del parámetro platformID”. Entonces, cuando platformID es 0 y esto define la plataforma Unicode, use la enumeración UnicodePlatformSpecificId, cuando platformID sea 1 (plataforma Macintosh), use la enumeración MacPlatformSpecificId, y cuando platformID sea 3 (plataforma Windows), use la enumeración MSPlatformSpecificId .
Las enumeraciones MSLanguageId y MacLanguageId están relacionadas con el parámetro languageID.
Utilice la enumeración MSLanguageId, cuando el ID de plataforma sea 3 (plataforma Windows) y utilice la enumeración MacLanguageId cuando el ID de plataforma sea 1 (plataforma Macintosh).
Procedamos ahora con la cuestión de obtener y actualizar entradas de la ’tabla de nombres'.
¿Cómo obtener registros de la tabla ’nombre'?
Empecemos por el método GetAllNameRecords(). Este método, como se desprende de su nombre, devuelve todas las entradas sin exclusiones de la tabla ’nombre’. En la práctica, este método no se utiliza con frecuencia ya que los usuarios en la mayoría de los casos no necesitan todas las entradas, por lo que para obtener la entrada necesaria, la lista de entradas debe filtrarse minuciosamente.
El problema es que incluso en una categoría lógica, por ejemplo FontFamily, las cadenas de datos de esta categoría pueden estar en diferentes idiomas. Por lo tanto, cada idioma necesita una entrada separada en la tabla ’nombre’ para esta categoría lógica. Por ejemplo, si los datos de la categoría FontFamily existieran en inglés, francés y alemán, la categoría FontFamily incluiría 3 entradas.
Además, la entrada de idioma se puede dividir en unas pocas entradas que coinciden con los valores de datos de cadena y el valor “languageID”, pero difieren con los valores de los parámetros “platformID” y “platformSpecificID”.
Para simplificar el muestreo de datos de la tabla ’nombre’, la biblioteca Aspose.Font ofrece los siguientes métodos:
- GetNameRecordsByNameId()- devuelve la lista de entradas para el conjunto por categoría lógica de usuario, definida por el parámetro
nameID
. - GetMultiLanguageNameById(): devuelve todas las entradas relevantes para la categoría lógica pasada nameID como un objeto de tipo MultiLanguageString. Por medio del objeto de tipo - MultiLanguageString, podemos encontrar todos los idiomas de esta categoría y obtener los datos de la cadena para el idioma establecido. Puede obtener la lista de todos los idiomas llamando al método GetAllLanguageIds() del tipo MultiLanguageString. Después de recibir la lista de idiomas, podemos llamar al método GetStringForLanguageId() para cada ID de idioma. Este método devuelve la cadena de datos escrita en este idioma.
La clase MultiLanguageString también ofrece los siguientes métodos:
ContainsString (string str): comprueba si una cadena pasada está presente dentro de todas las cadenas de idioma del objeto.
GetEnglishString() - devuelve una cadena escrita en inglés si se encuentra. Devuelve la primera cadena, cuyo ID de idioma es MSLanguageId.English_United_States, MSLanguageId.English_Australia, MSLanguageId.English_United_Kingdom, MSLanguageId.English_Canada o MSLanguageId.English_New_Zealand. Si no hay cadenas con el identificador de idioma relevante, el método devuelve la primera cadena de la lista.
GetAllStrings() - devuelve todas las cadenas de todos los idiomas que incluye el objeto.
El método más sencillo de usar de la clase TtfNameTable es GetNameById(), que fue diseñado para casos en los que solo necesita obtener el valor de la categoría establecida en inglés. Este método busca un registro, que corresponde a 2 criterios:
- Este registro está escrito en inglés, por lo que tiene el valor MSLanguageId.English_United_States o MSLanguageId.English_United_Kingdom para el parámetro languageID.
- Este registro tiene un ID de plataforma con el valor igual a FontEnvironment.Current.CurrentPlatformId (3 en la implementación actual, que declara la plataforma Microsoft).
¿Cómo agregar/actualizar registros en la tabla ’nombre'?
La clase TtfNameTable proporciona un método
AddName para agregar o actualizar registros en la tabla ’nombre’.
Este método crea la estructura del tipo
NameRecord y la inserta en la tabla ’nombre’. Si el registro coincide con el agregado por los parámetros platformID
, platformSpecificID
, languageID
y nameID
ya existe, el método no agrega un nuevo registro, sino que actualiza los datos de cadena en el registro existente usando el valor , definido por el parámetro nombre
.
El parámetro nameId
define la categoría de cadena lógica para un registro. Los parámetros platformId
, platformSpecificId
y languageId
se utilizan para establecer el idioma de la cadena. Y el último parámetro “nombre” se usa para establecer datos de cadena para un registro.
Ejemplos de uso de funciones del objeto TtfNameTable.
Agregar incluye y usa espacios de nombres:
1#include <system/text/string_builder.h>
2#include <system/enum.h>
3#include <system/console.h>
4#include <system/collections/list.h>
5#include <Aspose.Font.Cpp/src/TtfTables/TtfNameTable.h>
6#include <Aspose.Font.Cpp/src/TtfTables/TtfTableRepository.h>
7#include <Aspose.Font.Cpp/src/Ttf/TtfFont.h>
8#include <Aspose.Font.Cpp/src/MultiLanguageString.h>
9#include <Aspose.Font.Cpp/src/FontType.h>
10#include <Aspose.Font.Cpp/src/Font.h>
11
12usando el sistema de espacio de nombres;
13usando el espacio de nombres Aspose::Font::Ttf;
14usando el espacio de nombres Aspose::Font::TtfTables;
Declarar e inicializar una variable de fuente.
1 System::SharedPtr<Aspose::Font::Ttf::TtfFont> _font;
Los siguientes 2 fragmentos imprimen el valor de la categoría Nombre de fuente completo y producen el mismo resultado para la fuente Lora-Regular
1 //1
2 String fullFontName = _font->get_TtfTables()->get_NameTable()->GetNameById(TtfNameTable::NameId::FullName);
3 Console::WriteLine(String::Format(u"Full font name: {0}", fullFontName));
4 //2
5 String fullFontName = _font->get_TtfTables()->get_NameTable()->GetMultiLanguageNameById(TtfNameTable::NameId::FullName)->GetEnglishString();
6 Console::WriteLine(String::Format(u"Full font name: {0}", fullFontName));
Imprimiendo todo el contenido de la tabla ’nombre'.
El siguiente fragmento muestra cómo realizar esta operación.
1 System::ArrayPtr<TtfNameTable::NameId> ids = System::Enum<TtfNameTable::NameId>::GetValues();
2
3 for (TtfNameTable::NameId nameId : ids)
4 {
5 System::SharedPtr<MultiLanguageString> mlString = _font->get_TtfTables()->get_NameTable()->GetMultiLanguageNameById(nameId);
6 if (mlString == nullptr)
7 {
8 continue;
9 }
10 System::Console::WriteLine(System::String::Format(u"{0}: {1}", nameId, GetMultiLanguageStringValue(mlString)));
11 }
12
13 //Using of this method has no sense when strings from 'name' table have only single language, but it can be useful when font
14 //'name' table include multilingual strings
15 System::String MetadataExamples::GetMultiLanguageStringValue(System::SharedPtr<MultiLanguageString> mlString)
16 {
17 System::ArrayPtr<int32_t> languages = mlString->GetAllLanguageIds();
18 if (languages->get_Length() == 1)
19 {
20 return mlString->GetEnglishString();
21 }
22
23 System::SharedPtr<System::Text::StringBuilder> sb = System::MakeObject<System::Text::StringBuilder>();
24
25 for (int32_t i = 0; i < languages->get_Length(); i++)
26 {
27 int32_t langId = languages[i];
28 sb->Append(System::String::Format(u"{0}: {1}", System::Enum<TtfNameTable::MSLanguageId>::GetName((TtfNameTable::MSLanguageId)langId), mlString->GetStringForLanguageId(langId)));
29 if (i != (languages->get_Length() - 1))
30 {
31 sb->Append(u", ");
32 }
33 }
34
35 return sb->ToString();
36 }
Actualización de valores para las categorías “Nombre de subfamilia de fuentes” y “Descripción”
Para agregar o actualizar la entrada en la tabla ’nombre’ correctamente, necesitamos pasar los valores de los parámetros platformID, platformSpecificID e languageID que coincidan con los que ya están presentes en la tabla ’nombre’. Para ello, antes de actualizar los datos leeremos los registros existentes del tipo NameRecord relevantes a la categoría lógica de actualización, definida por el identificador de nombre.
1 //Struct for update operations
2 struct UpdateData
3 {
4 private:
5 TtfNameTable::NameId _nameId;
6 System::String _data;
7
8 public:
9 UpdateData(TtfNameTable::NameId nameId, String data)
10 {
11 this->_nameId = nameId;
12 this->_data = data;
13 }
14
15 TtfNameTable::NameId get_NameId() const
16 {
17 return this->_nameId;
18 }
19
20 String get_StringData() const
21 {
22 return this->_data;
23 }
24 };
25
26 UpdateData recordsToUpdate[] = {
27 UpdateData(TtfNameTable::NameId::FontSubfamily, String(u"Italic")),
28 UpdateData(TtfNameTable::NameId::Description, String(u"New description"))};
29
30 SharedPtr<TtfNameTable::NameRecord> firstRecord = nullptr;
31
32 for(UpdateData updateData : recordsToUpdate)
33 {
34 //Declare variable for NameRecord structure to use for update operations
35 SharedPtr<TtfNameTable::NameRecord> record = nullptr;
36
37 System::ArrayPtr<System::SharedPtr<TtfNameTable::NameRecord>> records = _font->get_TtfTables()->get_NameTable()->GetNameRecordsByNameId(updateData.get_NameId());
38
39 //In this example we will use only info from the first NameRecord structure returned to update font metadata.
40 //Many actual fonts require serious analyze of all NameRecords returned to update metadata correctly
41
42 //Initialize just created variables
43 if (records->get_Length() == 0)
44 {
45 //If no any record was found for current name identifer,
46 //we will use first found record for any name identifier
47 if (firstRecord == nullptr)
48 {
49 firstRecord = GetFirstExistingRecord(_font->get_TtfTables()->get_NameTable());
50 }
51 record = firstRecord;
52 }
53 else
54 {
55 record = records[0];
56 }
57
58 //Add or update record in 'name' table
59 _font->get_TtfTables()->get_NameTable()->AddName(updateData.get_NameId(), StaticCast<TtfNameTable::PlatformId>(record->get_PlatformId()), record->get_PlatformSpecificId(), record->get_LanguageId(), updateData.get_StringData());
60 }
61
62 System::SharedPtr<Aspose::Font::TtfTables::TtfNameTable::NameRecord> MetadataExamples::GetFirstExistingRecord(System::SharedPtr<Aspose::Font::TtfTables::TtfNameTable> table)
63 {
64 System::ArrayPtr<System::SharedPtr<TtfNameTable::NameRecord>> records;
65 for (TtfNameTable::NameId nameId : System::Enum<TtfNameTable::NameId>::GetValues())
66 {
67 records = table->GetNameRecordsByNameId(nameId);
68 if (records->get_Length() != 0)
69 {
70 return records[0];
71 }
72 }
73
74 return table->GetAllNameRecords()->idx_get(0);
75 }
Puede encontrar otros ejemplos para actualizar la tabla ’nombre’ en la prueba solution MetadataExamples.cpp.