Робота з таблицею 'name' | .NET

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

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

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

Існує 2 формати для таблиці ’name’ з номерами 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 має значення лише в контексті використовуваного параметра 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).

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

Клас TtfNameTable надає метод AddName для додавання або оновлення записів у таблиці «імен».

Цей метод створює структуру типу NameRecord і вставляє її в таблицю ’name’. Якщо запис збігається з доданим за параметрами platformID, platformSpecificID, languageID і nameID вже існує, метод не додає новий запис, а оновлює рядкові дані в існуючому записі за допомогою значення , визначений параметром name.

Параметр nameId визначає логічну категорію рядка для запису. Параметри platformId, platformSpecificId і languageId використовуються для встановлення мови рядка. І останній параметр name використовується для встановлення рядкових даних для запису.

Приклади використання функцій об’єкта TtfNameTable.

Включіть використання для таких просторів імен:

1    using System;
2    using System.IO;
3    using System.Text;
4    using Aspose.Font;
5    using Aspose.Font.Sources;
6    using Aspose.Font.Ttf;
7    using Aspose.Font.TtfTables;

Завантаження шрифту, використаного в прикладах

У наступних фрагментах передбачається, що TTF/montserrat-bold.ttf завантажено з DataDir у змінну TtfFont з іменем font. Процедуру завантаження описано в розділі Завантаження, вилучення даних і збереження шрифтів TrueType.

Наступні два фрагменти виводять значення Повна назва шрифту. Для прикладу шрифту обидва повертають Montserrat Bold.

1// Read the full font name by name ID
2
3string fullFontName = font.TtfTables.NameTable.GetNameById(TtfNameTable.NameId.FullName);
4Console.WriteLine("Full font name: {0}", fullFontName);
1// Read the English full font name from multilingual metadata
2
3string fullFontName = font.TtfTables.NameTable.GetMultiLanguageNameById(TtfNameTable.NameId.FullName).GetEnglishString();
4Console.WriteLine("Full font name: {0}", fullFontName);

Виведення записів для попередньо визначених ідентифікаторів назв

Наступний фрагмент перебирає попередньо визначені значення TtfNameTable.NameId і виводить доступні мовні рядки для кожної заповненої категорії.

 1// Print name-table strings for predefined name IDs
 2
 3TtfNameTable.NameId[] ids = Enum.GetValues<TtfNameTable.NameId>();
 4
 5foreach (TtfNameTable.NameId nameId in ids)
 6{
 7    MultiLanguageString? mlString = font.TtfTables.NameTable.GetMultiLanguageNameById(nameId);
 8    if (mlString == null)
 9        continue;
10    Console.WriteLine(string.Format("{0}: {1}", nameId, GetMultiLanguageStringValue(mlString)));
11}
12// Format the available language values for each predefined name ID.
13string GetMultiLanguageStringValue(MultiLanguageString mlString)
14{
15    int[] languages = mlString.GetAllLanguageIds();
16    if (languages.Length == 1)
17        return mlString.GetEnglishString();
18
19    StringBuilder sb = new StringBuilder();
20
21    for (int i = 0; i < languages.Length; i++)
22    {
23        int langId = languages[i];
24        sb.Append(String.Format("{0}: {1}", (Enum.GetName<TtfNameTable.MSLanguageId>(
25            (TtfNameTable.MSLanguageId)langId) ?? langId.ToString()), mlString.GetStringForLanguageId(langId)));
26        if (i != (languages.Length - 1))
27            sb.Append(", ");
28    }
29
30    return sb.ToString();
31}

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

Щоб додати або оновити запис у таблиці name, передайте ідентифікатори платформи, кодування платформи та мови, які відповідають наявним записам шрифту. У прикладі оновлюється перший відповідний запис Підродина шрифту. Оскільки в тестовому шрифті немає запису Опис, він створюється з ідентифікаторами першого доступного запису назви. Інші варіанти для платформ і мов не змінюються.

 1// Update font subfamily and description records
 2
 3// Use tuples so the complete operation fits in one method without a helper type.
 4(TtfNameTable.NameId NameId, string StringData)[] recordsToUpdate =
 5{
 6    (TtfNameTable.NameId.FontSubfamily, "Italic"),
 7    (TtfNameTable.NameId.Description, "New description")
 8};
 9
10TtfNameTable.NameRecord? firstRecord = null;
11foreach (var updateData in recordsToUpdate)
12{
13    TtfNameTable.NameRecord[] records = font.TtfTables.NameTable.GetNameRecordsByNameId(updateData.NameId);
14    TtfNameTable.NameRecord record;
15    // Update only the first matching record, preserving its platform and language.
16    // If the category is absent, use the identifiers of an existing name record.
17    if (records.Length == 0)
18    {
19        firstRecord ??= GetFirstExistingRecord(font.TtfTables.NameTable);
20        record = firstRecord;
21    }
22    else
23    {
24        record = records[0];
25    }
26
27    font.TtfTables.NameTable.AddName(updateData.NameId, (TtfNameTable.PlatformId)record.PlatformId,
28        record.PlatformSpecificId, record.LanguageId, updateData.StringData);
29}
30
31TtfNameTable.NameRecord GetFirstExistingRecord(TtfNameTable table)
32{
33    foreach (TtfNameTable.NameId nameId in Enum.GetValues<TtfNameTable.NameId>())
34    {
35        TtfNameTable.NameRecord[] records = table.GetNameRecordsByNameId(nameId);
36        if (records.Length != 0)
37            return records[0];
38    }
39
40    TtfNameTable.NameRecord[] allRecords = table.GetAllNameRecords();
41    if (allRecords.Length == 0)
42        throw new InvalidOperationException("The name table has no record to supply platform and language identifiers.");
43    return allRecords[0];
44}

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