Робота з таблицею 'name' | C++

Таблиця шрифтів TrueType ’name’ є сховищем для текстових рядків, пов’язаних із цим шрифтом. Ці рядки можуть бути написані різними мовами та можуть представляти різні сутності, такі як назви шрифтів, прізвища, імена дизайнерів, інформація про ліцензію, повідомлення про авторські права тощо. Коротше кажучи, рядки, які містяться в таблиці ’name’, описують метадані шрифту.

Схема таблиці ‘ім’я’.

Детальна специфікація для таблиці ’name’ доступна в Microsoft і Apple документації.

Існує 2 формати для таблиці «імен» з номерами 0 і 1 відповідно. У термінах таблиці «імен» ці номери форматів називаються версіями, тому формат 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 має значення лише в контексті використовуваного параметра platformID.

Наприклад, «languageID», що визначає англійську, США, дорівнює 0 для platformID = 1 (Mac) і 0x0409 для «platformID» = 3 (Windows).

Винятком є ​​лише languageID для формату таблиці імен 1, пов’язаний із рядком тегу мови, який ідентифікує мови незалежно від платформи.

Параметр nameID - це число, яке ідентифікує логічну категорію рядка, таку як назва шрифту, прізвище та інші. Існує попередньо визначений набір ідентифікаторів імен, який є однаковим для всіх платформ і мов.

Отже, кожен запис таблиці ’name’ умовно можна розділити на 3 частини:

  1. категорія логічного рядка,
  2. мова рядків,
  3. сам рядок.

Параметр nameID відноситься до першої частини, параметри platformID, platformSpecificID і languageID відносяться до другої частини.

Як працювати із записами таблиці “ім’я” за допомогою Aspose.Font?

Підтримка таблиці ’name’ забезпечується класом TtfNameTable. Далі розглянемо функціональність цього об’єкта.

Спочатку опишемо перерахування, необхідні для роботи з функціональністю класу TtfNameTable.- Перерахування NameID і PlatformId пов’язані з такими параметрами, описаними вище, як nameID і platformID.

Як було зазначено вище, «Значення параметрів platformSpecificID і languageID мають значення лише в контексті параметра platformID». Отже, коли platformID дорівнює 0 і це визначає платформу Unicode, використовуйте перерахування UnicodePlatformSpecificId, коли platformID дорівнює 1 (платформа Macintosh), використовуйте перерахування MacPlatformSpecificId, а коли platformID дорівнює 3 (платформа Windows), використовуйте перерахування MSPlatformSpecificId .

Перерахування MSLanguageId і MacLanguageId пов’язані з параметром languageID. Використовуйте перерахування MSLanguageId, коли platformID дорівнює 3 (платформа Windows), і використовуйте перерахування MacLanguageId, коли platformID дорівнює 1 (платформа Macintosh).

Давайте тепер приступимо до отримання та оновлення записів із «таблиці імен».

Як отримати записи з таблиці ’name'?

Почнемо з методу GetAllNameRecords(). Цей метод, як випливає з назви, повертає всі записи без виключення таблиці ім’я. На практиці цей метод не часто викликається, оскільки користувачам у більшості випадків не потрібні всі записи, тому, щоб отримати потрібний запис, список записів потрібно ретельно відфільтрувати.

Справа в тому, що навіть в одній логічній категорії, наприклад FontFamily, рядкові дані цієї категорії можуть бути різними мовами. Отже, кожна мова потребує окремого запису в таблиці «ім’я» для цієї логічної категорії. Наприклад, якщо дані для категорії FontFamily існують англійською, французькою та німецькою мовами, категорія FontFamily включатиме 3 записи.

Крім того, сам запис про мову можна розділити на кілька записів, які збігаються значеннями рядкових даних і значенням languageID, але відрізняються значеннями параметрів platformID і platformSpecificID.

Щоб спростити вибірку даних із таблиці ’name’, бібліотека Aspose.Font пропонує наступні методи:

Клас MultiLanguageString також пропонує наступні методи:

  1. Цей запис написано англійською мовою, тому він має значення MSLanguageId.English_United_States або MSLanguageId.English_United_Kingdom для параметра languageID.
  2. Цей запис має ідентифікатор платформи зі значенням FontEnvironment.Current.CurrentPlatformId (3 у поточній реалізації, яка декларує платформу Microsoft).

Як додати/оновити записи в таблиці “ім’я”?

Клас TtfNameTable надає метод AddName для додавання або оновлення записів у таблиці «імен». Цей метод створює структуру типу 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
12використання простору імен System;
13використання простору імен Aspose::Font::Ttf;
14використання простору імен 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));

Друк всього вмісту таблиці ’name'.

Наведений нижче фрагмент показує, як виконати цю операцію.

 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    }

Оновлення значень для категорій «Назва підродини шрифту» та «Опис»

Щоб правильно додати або оновити запис у таблиці name, нам потрібно передати значення параметрів platformID, platformSpecificID і languageID, які збігаються з тими, що вже присутні в таблиці name. Для цього перед оновленням даних ми прочитаємо існуючі записи типу 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	}

Інші приклади оновлення таблиці «імен» можна знайти в тесті solution MetadataExamples.cpp.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.