Старая Crystal Reports, шрифт TenseC и кириллица

Есть старючая программа (не скажу какая), использующая отчеты Crystal Reports (CR).
Была задача исправить в имеющемся .rpt файле шаблона отчета определенные надписи.
Изначально, версия CR, в которой был написан отчет, известна не была, а пересохраненый отчет в более поздней версии CR уже программой не читался.
Экспериментальным, мать его, путем версия Crystal Reports была найдена – это 8 (а точнее 8.5).

P.S.
Для таких же нубов, как был я, поясняю политику наименования версий CR:

  • До версии 10 – наименования версий арабскими цифрами.
  • Версия 11 – римской цифрой XI.
  • Затем – наименования в виде года выпуска: 2008, 2011, 2013.

Но при открытии отчета в CR 8.5, некоторые надписи на русском языке, у которых установлен шрифт TenseC, отображались квадратиками и вопросиками.
И тут пришлось погрузиться во вторую половину 90-х годов, во времена Windows 9x, и столкнуться с проблемой, до боли знакомой олдфагам, заставшим начало перехода Windows от однобайтных кодировок к Unicode.


Мат. часть

Полезные ссылки:
Языки, шрифты и кодировки как инкарнация Unicode – подробные статьи по этой теме
Кодировка текста ASCII (Windows 1251, CP866, KOI8-R) и Юникод (UTF 8, 16, 32) — как исправить проблему с кракозябрами” – большая подробная статья
Шрифты и Microsoft Windows – познавательная статья о кодировках и шрифтах в ранних версиях Windows (материал использовался для этой статьи)
Windows NT/2000/XP. Настройка. Шрифты – советы по использованию шрифтов на старых Windows
Наши представления о возможностях использования дополнительных символов
в русских шрифтах в MS Windows 95/98
 – описание проблемы перехода от однобайтовых кодовых страниц к Unicode
Кодировка. 8-битные и 16-битные приложения – хорошая статья простыми словами о сложных в данный момент понятиях кодирования текста, история кодировок

 

Суть проблемы со шрифтами TrueType (.ttf) заключается в том, что в некоторых кириллических шрифтах Unicode-индексы символов, изображающих русские буквы, соответствуют латинской кодовой таблице CP1252, а не кириллической CP1251.

На первый взгляд, для нормальной работы шрифтов как в программах, поддерживающих Unicode, так и в не-Unicode программах, необходимо и достаточно:

  • разместить символы в кодовом пространстве шрифта в соответствии с требованиями кириллической кодовой таблицы CP1251;
  • дать каждому символу корректный Unicode-индекс согласно CP1251;

  • (также) убедиться, что в шрифте присутствует малая буква «ё» с Unicode-индексом 0451, иначе шрифт может быть не распознан как кириллический.

Казалось бы, не-Unicode программам не важно, какой Unicode-индекс имеет русская буква «А», лишь бы она стояла в кодовой позиции 192. А Unicode программам, наоборот, все равно, в какой кодовой позиции стоит буква «А», лишь бы у нее был Unicode-индекс 0410. Размещение же символов в соответствии с предписаниями кодовой таблицы 1251 и обеспечивает нам нахождение символа с Unicode-индексом 0410 в кодовой позиции 192.

Кодовая страница 1251 (условно):

Кодовая позиция (dex) Unicode-индекс (hex)
192 0x0410

Шрифт:

Unicode-индекс (hex) Символ (глиф)
0x0410 А

Однако при этом обнаруживается неожиданный обратный эффект: русские буквы перестают отображаться в тех программах, с которыми ранее не было никаких проблем, если они не поддерживают работу с Unicode.

Объясняется это следующим. В реализации формата TrueType для MS Windows предусмотрена только линейная таблица кодирования шрифтов cmap, задающая соответствие между Unicode-индексами символов и их изображениями (глифами) в порядке возрастания Unicode-индексов.

Каким же образом осуществляется в Windows доступ к символам национальных алфавитов?
Определения поддерживаемых системой наборов национальных символов (т. е. кодовых страниц) содержатся в ресурсах gdi.exe, а также (для 32-битных Unicode-программ) в файлах национальной поддержки – NLS. Именно здесь и указывается, какому знакоместу из 256 возможных должны соответствовать Unicode-индексы нужных символов. Подобные таблицы соответствий принято называть «сечениями шрифтов».

Драйвер TrueType в GDI способен определить, какие конкретно кодовые страницы реально присутствуют в том или ином шрифте TTF, используя для этого специальный алгоритм.
В правильном Unicode-шрифте для каждого используемого национального набора символов (кроме исходного латинского) должно быть определено логическое сечение шрифта с использованием стандартных суффиксов.

В Unicode-программах такой шрифт будет виден только с исходным именем – никакие логические сечения в шрифтовых меню не появляются. В не-Unicode программах этот же шрифт будет появляться всеми имеющимися его сечениями. И если в Unicode-программах при работе с подобными шрифтами мы выбираем шрифт по его основному имени (например, Arial), то при переходе в не-Unicode программы мы должны постоянно помнить, что в них мы должны использовать шрифт не Arial, но Arial Cyr. Неудобства этого очевидны.

Остается только каким-то образом объяснить системе, что нас интересует кириллическое, а не какое-либо другое сечение шрифта. Для этого программа должна запросить не просто данный шрифт (например, “Arial”), но “Arial + Cyrillic script”. В программах с поддержкой Unicode для этого достаточно просто переключиться в русский регистр с помощью встроенного в Windows переключателя раскладки клавиатуры. На не-Unicode программы это не действует: здесь следует использовать перешедший из Windows 3.1 механизм создания логических шрифтов с использованием стандартных суффиксов шрифтов. Для этого необходимо для каждого Unicode-шрифта:

* при работе под Windows 9x в секции [FontSubstitutes] файла Win.ini записать строки вида:
Font <суффикс>,Charset=Font,Charset

* при работе под Windows NT в реестре по адресу
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
записать строки вида:
"Font <суффикс>,Charset"="Font,Charset"

Таким образом, для каждого используемого физического шрифта создается несколько логических шрифтов, отличающихся друг от друга суффиксами в имени – для каждого кодовой страницы Charset свой логический шрифт.

Например, если мы хотим использовать кириллическое и греческое сечение шрифта в не-Unicode программах, мы должны создать два логических шрифта следующим образом:
Arial Cyr,204=Arial,204
Arial Greek,161=Arial,161

, где:

161 – это код греческой кодовой страницы 1253 в Windows
204 – это код кириллической кодовой страницы 1251 в Windows

Charsets, или наборы символов

Код
(hex)

Код
(dec)

Наименование

Кодовая
страница

Суффикс
шрифта

Win 3.1

Win 9x

0x00

000

Western (Latin 1)

CP1252

 

+

+*

0x01

001

Unknown

 

 

0

0

0x02

002

Symbol

 

 

+

+

0x4D

077

Mac

 

Mac (?)

0

+*

0x80

128

Japanese

CP932

SJis

0

0x81

129

Hangeul

CP949

Hang

0

0x82

130

Hangeul (Johab)

CP1361

JOHAB

0

0x86

134

Chinese_GB2312

CP936

GB2312

0

0x88

136

Chinese_BIG5

CP950

ChiBIG

0

0xA1

161

Greek

CP1253

Greek

+

0xA2

162

Turkish (Latin 5)

CP1254

Tur

+

+

0xA3

163

Vietnamese

CP1258

Viet or Vietnamese

0xB1

177

Hebrew

CP1255

(Hebrew)

+

0xB2

178

Arabic

CP1256

(Arabic)

+

0xBA

186

Baltic

CP1257

Baltic

+

+

0xCC

204

Cyrillic

CP1251

Cyr

+

+

0xDE

222

Thai

CP874

Thai

0xEE

238

Central (Eastern)
European, (Latin 2)

CP1250

CE

+

+

0xFF

255

OEM/DOS

 

 

0

+* / 0

[О совместимости с Windows 3.1x]

Строго говоря, от нас не требуется давать логическому шрифту имя, совпадающее с именем физического шрифта, да и суффиксы в имени не обязательны. Однако рекомендуется соблюдать это правило по причине следующей недокументированной особенности Word’а 95: при переключении клавиатуры (и тем самым языка) он автоматически переключается на шрифт того же названия, добавляя к нему суффикс, соответствующий выбранному языку. И соответствие это определяется как раз жестко зашитыми в Word 95 допустимыми суффиксами национальных версий шрифтов: <пусто>, Cyr, CE, Baltic, Greek и Tur. Кроме того, таким образом мы обеспечиваем совместимость создаваемых нами документов с Windows 3.1x.


А теперь решение конкретной проблемы

Программа Crystal Reports 8.5, для отображения символов, написанных шрифтом с именем “TenseC” (т.е. без задания суффикса), обращается к латинской кодовой странице шрифта (TenseC,0).
Соответственно, происходит обращение к Unicode-кодам русских символов, которых в этой (латинской) кодовой странице нет.
Поэтому, нужно “перенаправить” программу на кириллическое сечение этого шрифта (TenseC,204).

Добавим в ветку
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
параметр (строку):
"TenseC, 0=TenseC,204"


И перезагрузим компутер.

 

Добавить комментарий

Ваш адрес email не будет опубликован.