Работа с таблицей name| API для С++
Таблица шрифтов TrueType «имя» — это хранилище текстовых строк, связанных с этим шрифтом. Эти строки могут быть написаны на разных языках и могут представлять различные объекты, такие как имена шрифтов, фамилии, имена дизайнеров, информацию о лицензии, уведомления об авторских правах и т. д.
Короче говоря, строки, содержащиеся в таблице «имя», описывают метаданные шрифта.
Схема таблицы «имя».
Существует два формата таблицы «имя» с номерами 0 и 1 соответственно. В таблице name эти номера форматов называются версией, поэтому формат 0 обозначается как версия 0, а формат 1 - как версия 1.
Формат 1 отличается от формата 0 идентификацией языка. Любая запись в таблице name имеет идентификатор языка, который используется для определения языка этой строки. А разница между форматом 0 и форматом 1 заключается в том, как интерпретируются эти идентификаторы языка.
Идентификаторы языка для формата 0 интерпретируются в зависимости от платформы, но идентификаторы языка для формата 1 связаны со строками языковых тегов, которые идентифицируют языки независимо от платформы.
Для большей точности формат 1 позволяет хранить идентификаторы языка обоих типов — идентификаторы с интерпретацией, зависящей от платформы, и идентификаторы, связанные со строками языковых тегов (т. е. независимые от платформы).
Библиотека Aspose.Font поддерживает формат 0 таблицы name. Поддержка формата 1 запланирована в будущих выпусках.
Независимо от формата таблицы name, любая запись в этой таблице основана на определенном компоненте — структуре NameRecord.
- идентификатор платформы(platformID),
- идентификатор платформы (platformSpecificID),
- идентификатор имени (nameID),
- и идентификатор языка (languageID).
Четыре основных параметра этой структуры:
Параметры «platformID», «platformSpecificID» и «languageID» используются для установки языка строки в зависимости от платформы. Значения параметров «platformSpecificID» и «languageID» имеют значение только в контексте параметра «platformID».
Например, platformSpecificID
, равный 0, определяет латинский алфавит для платформы Mac, и в то же время platformSpecificID
определяет латинский алфавит для платформы Windows.
Аналогично, значение «languageID» имеет значение только в контексте используемого параметра «ID платформы».
Например, languageID
, определяющий английский язык США, равен 0 для идентификатора платформы = 1 (Mac) и 0x0409 для platformID
= 3 (Windows).
Исключениями являются только languageID
для формата таблицы имен 1, связанного со строкой языкового тега, которая идентифицирует языки независимо от платформы.
Параметр nameID — это число, которое идентифицирует категорию логической строки, например имя шрифта, фамилию и другие. Существует предопределенный набор идентификаторов имен, который одинаков для всех платформ и языков.
- категория логической строки,
- строковый язык,
- сама строка.
Итак, каждую запись таблицы name условно можно разделить на 3 части:
Параметр «nameID» относится к первой части, параметры «platformID», «platformSpecificID» и «languageID» относятся ко второй части.
Как работать с записями таблицы «имя» с помощью Aspose.Font?
Поддержка таблицы name обеспечивается классом TtfNameTable. Далее рассмотрим функционал данного объекта.
- Перечисления NameID и PlatformId относятся к таким параметрам, описанным выше, как nameID и PlatformID.
- Перечисления UnicodePlatformSpecificId, MacPlatformSpecificId связаны с параметром PlatformSpecificID.
Сначала опишем перечисления, необходимые для работы с функциональностью класса TtfNameTable.
Как было сказано выше, «Значения параметров PlatformSpecificID и LanguageID имеют значение только в контексте параметра PlatformID». Итак, когда идентификатор платформы равен 0 и это определяет платформу Unicode, используйте перечисление UnicodePlatformSpecificId, когда идентификатор платформы равен 1 (платформа Macintosh), используйте перечисление MacPlatformSpecificId, а когда идентификатор платформы равен 3 (платформа Windows), используйте перечисление MSPlatformSpecificId .
Перечисления MSLanguageId и MacLanguageId относятся к параметру LanguageID. Используйте перечисление MSLanguageId, если идентификатор платформы равен 3 (платформа Windows), и используйте перечисление MacLanguageId, если идентификатор платформы равен 1 (платформа Macintosh).
Теперь приступим к получению и обновлению записей из таблицы имен.
Как получить записи из таблицы name?
Начнем с метода GetAllNameRecords(). Этот метод, как следует из названия, возвращает все записи без исключения таблицы name. На практике метод вызывается нечасто, так как пользователям в большинстве случаев не нужны все записи, поэтому для получения нужной записи список записей приходится тщательно фильтровать.
Дело в том, что даже в одной логической категории, например FontFamily, строковые данные этой категории могут быть на разных языках. Таким образом, для каждого языка требуется отдельная запись в таблице «имя» для этой логической категории. Например, если данные для категории FontFamily существуют на английском, французском и немецком языках, категория FontFamily будет включать 3 записи.
Кроме того, запись языка сама по себе может быть разделена на несколько записей, которые совпадают по значениям строковых данных и значению languageID
, но различаются значениями параметров platformID
и platformSpecificID
.
Класс MultiLanguageString также предлагает следующие методы:
- GetNameRecordsByNameId() - возвращает список записей для заданной пользователем логической категории, определенной параметром
nameID
. - GetMultiLanguageNameById() - возвращает все записи, соответствующие переданному nameID логической категории, в виде объекта типа MultiLanguageString. С помощью объекта типа - MultiLanguageString мы можем узнать все языки данной категории и получить строковые данные для заданного языка. Список всех языков можно получить, вызвав метод GetAllLanguageIds() типа MultiLanguageString. После получения списка языков мы можем вызвать метод GetStringForLanguageId() для каждого идентификатора языка. Этот метод возвращает строку данных, написанную на этом языке.
Для упрощения выборки данных из таблицы name библиотека Aspose.Font предлагает следующие методы:
ContainsString (string str) – проверяет, присутствует ли переданная строка внутри всех языковых строк объекта.
GetEnglishString() — возвращает строку, написанную на английском языке, если она найдена. Он возвращает первую строку, идентификатор языка которой — MSLanguageId.English_United_States, MSLanguageId.English_Australia, MSLanguageId.English_United_Kingdom, MSLanguageId.English_Canada или MSLanguageId.English_New_Zealand. Если строк с соответствующим идентификатором языка нет, метод возвращает первую строку списка.
GetAllStrings() — возвращает все строки всех языков, входящих в состав объекта.
Самый простой в использовании метод класса TtfNameTable — это GetNameById(), который был разработан для случаев, когда вам нужно только получить значение для заданной категории на английском языке. Этот метод ищет запись, соответствующую 2 критериям:
- Эта запись написана на английском языке, поэтому она имеет значение MSLanguageId.English_United_States или MSLanguageId.English_United_Kingdom для параметра LanguageID.
- Эта запись имеет идентификатор платформы со значением, равным FontEnvironment.Current.CurrentPlatformId (3 в текущей реализации, которая объявляет платформу Microsoft).
Как добавить/обновить записи в таблице «имя»?
Класс TtfNameTable предоставляет метод AddName для добавления или обновления записей в таблице name.
Этот метод создает структуру типа
NameRecord и вставляет ее в таблицу name. Если запись совпадает с добавленной по параметрам «platformID», «platformSpecificID», «languageID», «nameID» уже существует, метод не добавляет новую запись, а обновляет строковые данные в существующей записи, используя значение , определяемый параметром name
.
Параметр nameId определяет категорию логической строки для записи. Параметры «platformId», «platformSpecificId» и «languageId» используются для установки языка строки. И последний параметр name
используется для установки строковых данных для записи.
Примеры использования функций объекта TtfNameTable.
Добавьте включения и использование пространств имен:
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
12using namespace System;
13using namespace Aspose::Font::Ttf;
14using namespace Aspose::Font::TtfTables;
Объявление и инициализация переменной шрифта.
1 System::SharedPtr<Aspose::Font::Ttf::TtfFont> _font;
Следующие 2 фрагмента печатают значение для категории Полное имя шрифта и дают тот же результат для шрифта 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));
Печать всего содержимого таблицы «имя».
В приведенном ниже фрагменте показано, как выполнить эту операцию.
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 }
Обновление значений для категорий «Название подсемейства шрифта» и «Описание».
Чтобы правильно добавить или обновить запись в таблице «имя», нам необходимо передать значения параметров «platformID», «platformSpecificID» и «languageID», совпадающие с теми, которые уже присутствуют в таблице «имя». Для этого перед обновлением данных мы прочитаем существующие записи типа NameRecord, относящиеся к категории логики обновления, определенной идентификатором имени.
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 }
Другие примеры обновления таблицы name вы можете найти в тесте solution MetadataExamples.cpp.