如何通过 WinAPI 使用不带连字的字体?
How to use font without ligatures via WinAPI?
我正在尝试创建具有自定义输出的简单应用程序。我正在使用 CreateFont 函数来加载具有特定选项的等宽字体。结果,文字被绘制(DrawText)连字如fi.
如何禁用它?
非常抱歉我的英语不好
正在创建字体
normal = CreateFont(char_height, 0, 0, 0, FW_NORMAL, 0, 0, 0,
RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, 5,
FIXED_PITCH | FF_DONTCARE, "Menlo");
bold = CreateFont(char_height, 0, 0, 0, FW_BOLD, 0, 0, 0,
RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, 5,
FIXED_PITCH | FF_DONTCARE, "Menlo");
打印
void Console::Print(string text, int color, int weight) {
RECT r;
r.top = padding + temp_y * (char_height + space_y);
r.bottom = r.top + char_height;
r.left = padding + temp_x * char_width;
r.right = padding + length();
HDC hdc = GetDC(hwnd);
SetTextColor(hdc, color);
SetBkColor(hdc, RGB(43, 48, 59));
SelectObject(GetDC(hwnd), weight == WEIGHT_NORMAL ? normal : bold);
DrawText(GetDC(hwnd), text.c_str(), text.length(), &r, DT_LEFT);
temp_x += text.length();
}
当前输出(注意单词"offline"):
期望的输出:
根本问题似乎是你的字体坏了。我不确定为什么等宽(固定间距)字体会有连字信息。
解决方案 1
将 ExtTextOutW 与 ETO_IGNORELANGUAGE
结合使用。您可能会失去其他功能(如双向、数字替换、复杂脚本的整形),但它似乎确实可以防止字距调整和连字,因此它可能适合您的目的。
::ExtTextOutW(hdc, x, y, ETO_IGNORELANGUAGE, &rc, msg.c_str(), msg.size(), nullptr);
我用 Gabriola 字体进行了测试,因为我没有 Menlo 或 Meslo。 Gabriola 是一种可变间距字体,但它具有独特的连字,使其易于识别,尤其是 fi
.
解决方案 2
第二种方法具有相同的缺点,即在循环中使用 TextOut 逐个字符地绘制字符串。这有点棘手,因为您必须担心 Unicode 代理项对、裁剪和更新当前位置。
const auto old_alignment = ::SetTextAlign(hdc, TA_UPDATECP);
const auto old_mode = ::SetBkMode(hdc, TRANSPARENT);
::MoveToEx(hdc, x, y, nullptr);
// Loop simplified for demo. This doesn't handle Unicode surrogate pairs.
for (auto ch : msg) {
::TextOutW(hdc, 0, 0, &ch, 1);
}
::SetBkMode(hdc, old_mode);
::SetTextAlign(hdc, old_alignment);
这产生了与第一个解决方案相同的结果。
无解
请注意,我之前使用 GetCharacterPlacement without the GCP_LIGATE flag followed by ExtTextOut 和 ETO_GLYPH_INDEX 的想法是行不通的。即使没有 GCP_LIGATE 标志,从 GetCharacterPlacement 返回的字形仍然包含连字。
// DOES NOT WORK
GCP_RESULTSW results = {sizeof(results)};
WCHAR modified[64] = L""; // FIXED BUFFER LENGTHS JUST FOR TESTING
results.lpOutString = modified;
int deltas[64] = {0};
results.lpDx = deltas;
WCHAR glyphs[64] = L"";
glyphs[0] = 1;
results.lpGlyphs = glyphs;
results.nGlyphs = ARRAYSIZE(glyphs);
const DWORD flags = GCP_REORDER; // but not GCP_LIGATE or GCP_USEKERNING
::GetCharacterPlacementW(hdc, msg.c_str(), msg.size(), 0, &results, flags);
::ExtTextOutW(hdc, x, y, ETO_GLYPH_INDEX, &rc, glyphs, results.nGlyphs, deltas);
我正在尝试创建具有自定义输出的简单应用程序。我正在使用 CreateFont 函数来加载具有特定选项的等宽字体。结果,文字被绘制(DrawText)连字如fi.
如何禁用它?
非常抱歉我的英语不好
正在创建字体
normal = CreateFont(char_height, 0, 0, 0, FW_NORMAL, 0, 0, 0,
RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, 5,
FIXED_PITCH | FF_DONTCARE, "Menlo");
bold = CreateFont(char_height, 0, 0, 0, FW_BOLD, 0, 0, 0,
RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, 5,
FIXED_PITCH | FF_DONTCARE, "Menlo");
打印
void Console::Print(string text, int color, int weight) {
RECT r;
r.top = padding + temp_y * (char_height + space_y);
r.bottom = r.top + char_height;
r.left = padding + temp_x * char_width;
r.right = padding + length();
HDC hdc = GetDC(hwnd);
SetTextColor(hdc, color);
SetBkColor(hdc, RGB(43, 48, 59));
SelectObject(GetDC(hwnd), weight == WEIGHT_NORMAL ? normal : bold);
DrawText(GetDC(hwnd), text.c_str(), text.length(), &r, DT_LEFT);
temp_x += text.length();
}
当前输出(注意单词"offline"):
期望的输出:
根本问题似乎是你的字体坏了。我不确定为什么等宽(固定间距)字体会有连字信息。
解决方案 1
将 ExtTextOutW 与 ETO_IGNORELANGUAGE
结合使用。您可能会失去其他功能(如双向、数字替换、复杂脚本的整形),但它似乎确实可以防止字距调整和连字,因此它可能适合您的目的。
::ExtTextOutW(hdc, x, y, ETO_IGNORELANGUAGE, &rc, msg.c_str(), msg.size(), nullptr);
我用 Gabriola 字体进行了测试,因为我没有 Menlo 或 Meslo。 Gabriola 是一种可变间距字体,但它具有独特的连字,使其易于识别,尤其是 fi
.
解决方案 2
第二种方法具有相同的缺点,即在循环中使用 TextOut 逐个字符地绘制字符串。这有点棘手,因为您必须担心 Unicode 代理项对、裁剪和更新当前位置。
const auto old_alignment = ::SetTextAlign(hdc, TA_UPDATECP);
const auto old_mode = ::SetBkMode(hdc, TRANSPARENT);
::MoveToEx(hdc, x, y, nullptr);
// Loop simplified for demo. This doesn't handle Unicode surrogate pairs.
for (auto ch : msg) {
::TextOutW(hdc, 0, 0, &ch, 1);
}
::SetBkMode(hdc, old_mode);
::SetTextAlign(hdc, old_alignment);
这产生了与第一个解决方案相同的结果。
无解
请注意,我之前使用 GetCharacterPlacement without the GCP_LIGATE flag followed by ExtTextOut 和 ETO_GLYPH_INDEX 的想法是行不通的。即使没有 GCP_LIGATE 标志,从 GetCharacterPlacement 返回的字形仍然包含连字。
// DOES NOT WORK
GCP_RESULTSW results = {sizeof(results)};
WCHAR modified[64] = L""; // FIXED BUFFER LENGTHS JUST FOR TESTING
results.lpOutString = modified;
int deltas[64] = {0};
results.lpDx = deltas;
WCHAR glyphs[64] = L"";
glyphs[0] = 1;
results.lpGlyphs = glyphs;
results.nGlyphs = ARRAYSIZE(glyphs);
const DWORD flags = GCP_REORDER; // but not GCP_LIGATE or GCP_USEKERNING
::GetCharacterPlacementW(hdc, msg.c_str(), msg.size(), 0, &results, flags);
::ExtTextOutW(hdc, x, y, ETO_GLYPH_INDEX, &rc, glyphs, results.nGlyphs, deltas);