Я хочу отобразить символ языка каннада (используется в Индии). Для правильного отображения требуется перевязка. Я использую следующий код MFC:
Конструктор:
mi_Font.CreateFontW(85, 0, 0, 0, 500, 0, 0, 0,
DEFAULT_CHARSET, 0, 0, 0, 0, L"Tunga");
в OnPaint ():
HDC h_DC = ::GetDC(m_hWnd);
HFONT h_OldFont = (HFONT)::SelectObject(h_DC, mi_Font);
WCHAR u16_Face[100];
::GetTextFace(h_DC, 100, u16_Face);
if (wcscmp(u16_Face, L"Tunga") != 0)
throw "Invalid font."; // Just assure that the font has been created correctly
WCHAR u16_Glyphs[100] = {0};
GCP_RESULTS k_Results = {0};
k_Results.lStructSize = sizeof(k_Results);
k_Results.lpGlyphs = u16_Glyphs;
k_Results.nGlyphs = 100;
const WCHAR* u16_Str = L"\x0C95\x0CCD\x0C95\x0CBE"; // Kannada
int s32_Len = (int)wcslen(u16_Str);
GetCharacterPlacement(h_DC, u16_Str, s32_Len, 0, &k_Results, GCP_LIGATE);
ExtTextOut(h_DC, 0, 0, ETO_GLYPH_INDEX, NULL, u16_Glyphs, k_Results.nGlyphs, NULL);
SelectObject(h_DC, h_OldFont);
::ReleaseDC(m_hWnd, h_DC);
Этот код прекрасно работает в Windows 7. Но в Windows XP флаг GCP_LIGATE не действует. (В Windows 7 он работает даже без этого флага!)
Чтобы убедиться, что шрифт не является проблемой, я скопировал один и тот же файл шрифта (Tunga.ttf) на оба компьютера.
Проблема в GetCharacterPlacement()
,
На XP он возвращает индексы глифов 66,114,66,101 (без лигирования)
На Win7 он возвращает 144 101 180 (лигированный)
Я не могу поверить, что Windows XP не может правильно отображать каннаду, потому что GetCharacterPlacement()
уже была введена в Windows 2000!
И когда я вручную ввожу значения в k_Result:
u16_Glyphs[0] = 144;
u16_Glyphs[1] = 101;
u16_Glyphs[2] = 180;
k_Results.nGlyphs = 3;
ExtTextOut()
показывает правильный глиф также на XP.
Когда я проверяю возвращаемое значение из GetFontLanguageInfo(h_DC)
У меня на обеих операционных системах одинаковое значение: 0x40000.
Кто-нибудь имеет опыт работы с этим API?
Я исследовал гораздо больше о GetCharacterPlacement () и других функциях GDI.
Помимо того факта, что лигатуры не отображаются правильно в Windowx XP, в этой функции есть СЕВЕРНЫЕ ошибки даже в Windows 7. Одним из них является то, что возвращаемое значение, которое должно содержать ширину и высоту нарисованного символа, является совершенно неправильным для некоторых символов. ,
Странно то, что Windows правильно рисует цвет фона (белый на моих скриншотах выше), но функция не всегда возвращает эту же область. Для некоторых лигатур шириной 170 пикселей возвращается совершенно неправильное значение 93.
Кроме того, значения Delta-X, которые могут быть запрошены через GCP_RESULTS.lpDx, в некоторых случаях могут быть полностью неверными, хотя символ отображается правильно.
И наконец, когда какой-то шрифт нарисован курсивом, функция возвращает точно такие же координаты, как если бы она была нарисована обычным, хотя курсив шире.
Я тоже проверял GetTextExtentPoint32()
, GetTextExtentPointI()
а также DrawText(...DT_CALCRECT)
, Все они возвращают одинаковую неправильную ширину.
Пример:
Когда вы рисуете символ «Т» курсивом, все эти функции возвращают ширину 35 пикселей. Как вы можете измерить себя на скриншоте ниже, реальный с 64 пикселей. 35 пикселей являются правильными для обычного символа. Стиль курсива просто игнорируется. Это также относится к Windows 7.
ЗАКЛЮЧЕНИЕ:
Забудьте об измерении шрифтов с помощью одной из этих функций. Они все глючные. Если вы тщательно протестируете множество шрифтов и языков, таких как телугу о каннада, вы обнаружите случаи, когда они возвращают ерунду.
Теперь я понимаю, почему виртуальная машина Java не использует API-интерфейс Windows для рисования текста. Если вы изучите исходный код Java, вы обнаружите, что они загружают файлы TTF напрямую и выполняют все вычисления и рисование со своим собственным кодом.
Я нашел это в блоге MSDN:
GetCharacterPlacement не учитывает кернинг
Недавно я столкнулся с той же ошибкой. GetCharacterPlacement () вернул неверные результаты на 3 компьютерах и правильные значения на 4 других. Затем я обнаружил, что на всех компьютерах, где GetCharacterPlacement () не работал должным образом, восточноазиатские языки были установлены и не были установлены на других компьютерах. Я установил восточноазиатские языки на ПК, где GetCharacterPlacement () работал нормально, и он прекратил работу сразу после установки! Затем я удалил восточноазиатские языки, и код снова начал работать отлично.
Это не имеет прямого отношения, но я пришел сюда, потому что у меня также возникают проблемы с GetCharacterPlacement на XP (многие из моих клиентов все еще используют XP).
Оказывается, что в XP параметр GCP_RESULTS должен быть выровнен по 4-байтовой границе; в противном случае вызов не выполняется. В Windows 7 его не нужно выравнивать.
Кроме того, GetLastError () не имеет никакого отношения к вызову GetCharacterPlacement.
Я понимаю, что в приведенном выше примере он выровнен.