Шрифт Unicode сопоставление глифа с реальными символами - PullRequest
5 голосов
/ 15 февраля 2012

Я пытаюсь отобразить все глифы шрифтом. Я использую GetFontUnicodeRanges для получения доступных символов, затем создаю растровое изображение со всеми доступными символами и их индексами рядом с каждым.

Я использовал шрифт "Wingdings 2" в качестве контрольного примера и сравнил его с тем, что вижу в Windows * charmap.exe. Я вижу, что, хотя все символы появляются, некоторые символы появляются более одного раза (всего 480 символов в этом шрифте, не являющемся юникодом), и позиции не такие, как в charmap (например, круговой символ среднего размера в charmap расположен как 0x97, и в шрифте это глиф 0xF097, и я также думаю, что это тот же самый в 0x2014).

Я хочу использовать шрифт как «обычный» способ, то есть я хочу видеть те же данные, что и в charmap.exe (и в примечании, я также хотел бы знать, является ли шрифт Unicode или шрифт ascii, как показывает charmap). По сути, вы можете сказать, что я пытаюсь написать свой собственный charmap с нуля.

Как я могу заполнить эти недостающие данные? Я просматривал шрифты и текстовые API-интерфейсы Windows, но не смог найти ничего, что могло бы мне помочь, поэтому мне не хватает некоторых соответствующих API-интерфейсов. Что они?

Ответы [ 3 ]

6 голосов
/ 16 февраля 2012

После долгих попыток с GetFontData и недостатком документации (ну, не совсем так, но она не очень хорошо организована, а некоторые данные действительно отсутствуют), я нашел способ написать свой собственный CharMap.Вот что я обнаружил во время разработки:

  1. Документация скажет вам, что можно использовать "хитрость", поскольку данные о местоположении глифа поступают сразу после массивов в таблице cmap.Это не значит, что это IN таблица cmap.На самом деле они находятся в таблице loca.

  2. Вам также необходимо прочитать таблицу head для флага формата местоположения (смещение 34),и maxp таблица для числа число глифов поле (смещение 4).

  3. Кажется, что в символьных шрифтах (вы можете сказать, является ли шрифтшрифт символа, если идентификатор кодировки заголовка cmap равен 0, по крайней мере, в формате TTF 4, который является форматом Microsoft), символы добавляются 0xF000 к их фактическому индексу, поэтому вместо обычных кодов ASCII вы получаете значение Unicode вдальний конец таблицы Unicode.Я вычитал 0xF000 из каждого символьного кода и тестировал шрифты Wingdings [2,3] и Webdings, и это работало просто отлично.

Я много использовал официальную документацию: www.microsoft.com/typography/tt/ttf_spec/ttch02.doc и код ссылки: http://support.microsoft.com/kb/241020.

Код ссылки написан на C, поэтому для записи на C # Iчитать все данные в byte[] буферы и «вручную» читать каждый элемент из него.

2 голосов
/ 26 августа 2014

Я тоже пережил этот кошмар много лет назад, и теперь я много знаю обо всем этом. Я подумал, что должен ответить и дать несколько ответов.

1) Вы не можете предполагать, что «loca» следует за «cmap». Порядок может варьироваться в зависимости от шрифта. Расположение каждого блока определяется OffsetTable, который обычно начинается с байта 0 файла шрифта. (http://www.microsoft.com/typography/otspec/otff.htm)

2) Вы не можете предполагать, что «идентификатор кодировки заголовка cmap равен 0, по крайней мере, в формате TTF 4» означает символьные шрифты. Я точно знаю, что некоторые старые арабские шрифты также используют эту кодировку. На сегодняшний день я до сих пор не знаю, как их дифференцировать. Винда делает это но я не знаю как. Я не знаю, как точно знать, что шрифт является символьным шрифтом. Даже проверки таблицы OS / 2 на бит 32 кодовой страницы недостаточно во многих случаях.

3) Вы не можете просто использовать магический номер 0xF000 и добавить его к своему маленькому 0-255 числу, чтобы получить символ, который даст вам отображение глифа, которое вы ищете. Это связано с тем, что эти небольшие коды ASCII от 0 до 255 будут различаться в зависимости от языкового стандарта вашей системы.

Шрифт символов - это особый способ их обработки в Windows.

В отличие от обычного шрифта, в котором сопоставление между глифами и символами является статическим, сопоставление шрифтов символов зависит от системной кодовой страницы по умолчанию для приложения, не являющегося кодировкой Unicode, или CP_ACP.

Например, представьте, что ваш шрифт символа имеет следующий символ: «%». Если в вашей системе по умолчанию используется CP 1252, то для рендеринга этого глифа вам, например, необходимо отобразить значение символа '0xC2'.

Если в вашей системе по умолчанию используется CP 1251, то для рендеринга этого глифа вам, например, необходимо отразить значение символа '0x416', которое совершенно другое.

Иначе говоря, диапазоны Юникода шрифта варьируются в зависимости от кодовой страницы, не являющейся кодировкой Юникода по умолчанию!

После исследования мы обнаружили, что действительными символьными значениями для шрифтов являются значения, полученные путем преобразования 0–255, если они были значением CP_ACP в Unicode.

Что это значит? Это означает, что вы хотите использовать MultiByteToWideChar с CP_ACP, чтобы получить сопоставление значений от 0 до 255 с их локализованным значением Юникода в зависимости от языкового стандарта вашей системы (CP_ACP).

Таким образом, это даст вам карту типа:

ASCII -> localized non-static UNICODE
0x00 -> 0x00
0x01 -> 0x01
0x02 -> 0x02
...
0xC2 -> 0x416 <----- This is correct : the value will be different in some cases.
...
0xE3 -> 0xE3

Значения от 0xF000 до 0xF0FF являются статическими значениями UNICODE: они никогда не меняются.

Таким образом, чтобы получить идентификатор глифа для «локализованного нестатического UNICODE», сначала вы используете свою карту выше, чтобы найти соответствующее значение ASCII, а затем добавляете к ней 0xF000, а затем получаете идентификатор глифа для этого.

Конечно, это бессмысленное не задокументировано MS ... или я никогда не смог бы его найти.

1 голос
/ 15 февраля 2012

Я никогда не рассматривал "WingDings 2" подробно, но очень часто глифы используются повторно для разных символов. Например, заглавная латинская буква A и заглавная греческая альфа часто являются одним и тем же глифом.

Однако, я думаю, равенство 0x97, 0xF097 и 0x2014 - это своего рода хак для работы с windows-1252. В кодовой странице windows-1252 0x97 - это тире, а в Unicode - 0x2014. 0xF097 находится в зоне частного использования; Я предполагаю, что это обеспечивает Unicode-совместимый (и обратимый) способ кодирования windows-1252 0x97.

По моему опыту, самый надежный способ получить однозначный список символов юникода, поддерживаемых шрифтом, - это проанализировать таблицу cmap из файла ttf. Это немного хлопотно (cmap поддерживает что-то вроде шести разных кодировок), но это задокументировано онлайн. Вы можете использовать функцию GetFontData , чтобы получить необработанные данные, или напрямую проанализировать ttf.

charmap использует функцию GetFontData, а код включает в себя строку "cmap", предполагая, что charmap также делает это.

В состав средств отладки Windows SDK входит logger.exe, который записывает все API, используемые приложением. Вы можете использовать это, если хотите быть действительно уверенным в том, что делает charmap.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...