Работа с таблицей name | С++

Таблица шрифтов TrueType «имя» — это хранилище текстовых строк, связанных с этим шрифтом. Эти строки могут быть написаны на разных языках и могут представлять различные объекты, такие как имена шрифтов, фамилии, имена дизайнеров, информацию о лицензии, уведомления об авторских правах и т. д.

Короче говоря, строки, содержащиеся в таблице «имя», описывают метаданные шрифта.

Схема таблицы «имя».

Подробная спецификация таблицы «name» доступна в документации Microsoft и Apple.

Существует два формата таблицы «имя» с номерами 0 и 1 соответственно. В таблице name эти номера форматов называются версией, поэтому формат 0 обозначается как версия 0, а формат 1 - как версия 1.

Формат 1 отличается от формата 0 идентификацией языка. Любая запись в таблице name имеет идентификатор языка, который используется для определения языка этой строки. А разница между форматом 0 и форматом 1 заключается в том, как интерпретируются эти идентификаторы языка.

Идентификаторы языка для формата 0 интерпретируются в зависимости от платформы, но идентификаторы языка для формата 1 связаны со строками языковых тегов, которые идентифицируют языки независимо от платформы.

Для большей точности формат 1 позволяет хранить идентификаторы языка обоих типов — идентификаторы с интерпретацией, зависящей от платформы, и идентификаторы, связанные со строками языковых тегов (т. е. независимые от платформы).

Библиотека Aspose.Font поддерживает формат 0 таблицы name. Поддержка формата 1 запланирована в будущих выпусках.

Независимо от формата таблицы name, любая запись в этой таблице основана на определенном компоненте — структуре NameRecord.

Четыре основных параметра этой структуры:

Параметры «platformID», «platformSpecificID» и «languageID» используются для установки языка строки в зависимости от платформы. Значения параметров «platformSpecificID» и «languageID» имеют значение только в контексте параметра «platformID».

Например, platformSpecificID, равный 0, определяет латинский алфавит для платформы Mac, и в то же время platformSpecificID определяет латинский алфавит для платформы Windows. Аналогично, значение «languageID» имеет значение только в контексте используемого параметра «ID платформы».

Например, languageID, определяющий английский язык США, равен 0 для идентификатора платформы = 1 (Mac) и 0x0409 для platformID = 3 (Windows).

Исключениями являются только languageID для формата таблицы имен 1, связанного со строкой языкового тега, которая идентифицирует языки независимо от платформы.

Параметр nameID — это число, которое идентифицирует категорию логической строки, например имя шрифта, фамилию и другие. Существует предопределенный набор идентификаторов имен, который одинаков для всех платформ и языков.

  1. категория логической строки,
  2. строковый язык,
  3. сама строка.

Итак, каждую запись таблицы name условно можно разделить на 3 части:

Параметр «nameID» относится к первой части, параметры «platformID», «platformSpecificID» и «languageID» относятся ко второй части.

Как работать с записями таблицы «имя» с помощью Aspose.Font?

Поддержка таблицы name обеспечивается классом TtfNameTable. Далее рассмотрим функционал данного объекта.

Сначала опишем перечисления, необходимые для работы с функциональностью класса 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 также предлагает следующие методы:

Для упрощения выборки данных из таблицы name библиотека Aspose.Font предлагает следующие методы:

  1. Эта запись написана на английском языке, поэтому она имеет значение MSLanguageId.English_United_States или MSLanguageId.English_United_Kingdom для параметра LanguageID.
  2. Эта запись имеет идентификатор платформы со значением, равным 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.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.