【问题标题】:How to use font without ligatures via WinAPI?如何通过 WinAPI 使用没有连字的字体?
【发布时间】:2015-07-02 07:43:28
【问题描述】:

我正在尝试使用自定义输出创建简单的应用程序。我正在使用 CreateFont 函数来加载具有特定选项的等宽字体。结果,文本已经用fi等连字绘制(DrawText)。

如何禁用此功能?

我很抱歉我的英语不好

创建字体

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();
}

当前输出(注意单词“离线”):

期望的输出:

【问题讨论】:

  • 不清楚你在问什么。您能否提供您的代码的 sn-p 和输出的屏幕截图?
  • @RemyLebeau 我添加了一些信息
  • 请内联发布屏幕截图,不要发布链接(BTW 已损坏)。
  • 你从哪里得到这个字体?
  • 也许可以尝试找到它的另一个版本,或者另一种看起来像它的字体,看看是否可行。

标签: c++ winapi


【解决方案1】:

根本问题似乎是你的字体坏了。我不确定为什么等宽(固定间距)字体会有连字信息。

解决方案 1

ExtTextOutWETO_IGNORELANGUAGE 一起使用。您可能会失去其他功能(例如 bi-di、数字替换、复杂脚本的整形),但它似乎确实可以防止字距调整和连接,因此它可能适合您的目的。

::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);

这产生了与第一个解决方案相同的结果。

无解

请注意,我之前使用不带 GCP_LIGATE 标志的 GetCharacterPlacement 后跟带 ETO_GLYPH_INDEX 的 ExtTextOut 的想法不起作用。即使没有 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);

【讨论】:

  • “我不知道为什么等宽(固定间距)字体会有连字信息”——很多人都有。考虑Fira Code。它对编程特别有用:在那个网站上,看看十六进制 0x0 中的 x 是如何变化的,或者比较运算符 !=、==、
  • @David M:我不知道“许多”固定间距字体是否可以做到这一点。 Fira C0de 非常专门用于特定任务,看起来那些两个字符的连字仍然占据两列,这在固定间距字体中比像 OP 字体中的 fl 连字更有意义。跨度>
  • 这很公平 - 如果我可以编辑评论,我会删除“很多”。我也见过moderately highly voted VS UserVoice 为 Consolas 请求连字,我猜 Fira Code + maybe-Consolas + Pragmata Pro + 其他几个,十个顶部的组合变成了“许多”。对于代码字体来说,这是一件有趣的事情。偏振。许多编辑可以选择将其关闭。
猜你喜欢
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
  • 1970-01-01
相关资源
最近更新 更多