【问题标题】:DrawText with outline using GDI (C++)使用 GDI (C++) 绘制带有轮廓的 DrawText
【发布时间】:2017-10-31 02:35:00
【问题描述】:

我正在使用此代码对来自网络摄像头的帧进行签名:

Font = CreateFont(18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, "times");

...

HDC hDC = CreateCompatibleDC(NULL);
unsigned char * img = 0;
HBITMAP hBitmap = CreateDIBSection(hDC, &BMI, DIB_RGB_COLORS, (void**)&img, NULL, 0);
memcpy(img, CameraFrame.data, CameraFrame.size());
free(CameraFrame.data);
CameraFrame.data = img;
SelectObject(hDC, hBitmap);
SelectObject(hDC, Font);
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(255,255,255));
string Text = "Test";
DrawTextA(hDC, Text.c_str(), Text.size(), &rect, DT_CENTER | DT_WORDBREAK);
DeleteDC(hDC);

当然,框架的色阶会有所不同,无论如何我都需要文字可见。

如何DrawText带轮廓?例如,黑色轮廓的白色文本。

【问题讨论】:

  • 据我所知,这不是(很容易)使用普通 GDI 实现的。另一方面,GDI+ 允许您这样做。有一篇包含大量示例的 CodeProject 文章 (Outline Text)。
  • 其实很简单。使用 GDI 路径。

标签: c++ winapi gdi


【解决方案1】:

两种方法:

  • 将文本绘制为黑色,但将其放大 2 个像素(祝你好运)并偏移 (-1,-1),然后通常在中心为白色。

  • 将文本绘制为黑色,但偏移{ (-1,-1), (1,1), (-1,1), (1,-1) },然后在中心绘制为白色。

【讨论】:

  • 第一个建议不起作用,因为背景(轮廓)不会随文本水平缩放。第二个建议不会创建轮廓,而是类似于阴影效果。
  • 我已经在 pass 中使用了为此目的建议的第二种技术,但我发现还需要使用总共八个偏移量,建议的四个对角线加上四个正交的。即使字符有对角线,这也会使轮廓连续。您可以争论它是轮廓还是阴影,但它可以很好地将文本与背景分开。
  • 是的,在将我的字体系统升级到有符号距离场之前,我已经使用了多年的技术。
  • 第二个解决方案给出了类似 CSS text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; 的结果——正是我所需要的!非常感谢!
【解决方案2】:

使用 GDI,您可以使用 BeginPath、DrawText、EndPath,然后是 StrokeAndFillPath,只要您使用“轮廓”字体(如 TrueType 或 OpenType)。

  ::BeginPath(ps.hdc);
  RECT rc;
  GetClientRect(&rc);
  ::DrawTextW(ps.hdc, L"Hello", 5, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  ::EndPath(ps.hdc);
  ::StrokeAndFillPath(ps.hdc);

StrokeAndFillPath 将使用当前选定的笔作为轮廓,并使用当前选定的画笔来填充它。您可以在 BeginPath/EndPath 中使用 TextOut 或其他 GDI 调用。

您不会像使用常规文本输出那样获得任何抗锯齿功能,因此它不会像常规 ClearType 文本那样清晰。在更大的尺寸下,这不是一个大问题。

【讨论】:

  • 这真的有效吗?因为DrawText() 未列为可与BeginPath() 一起使用的受支持API 之一。如果是这样,它要么是一个文档错误,要么是一个我不会依赖的未记录的实现细节。
  • 我从工作代码中提取了它。我多年前就学会了这项技术,所以听到它没有记录在案,我感到很惊讶。 DrawText 归结为 TextOut 或 ExtTextOut 的道德等价物,所以如果它不起作用,我会感到惊讶。
  • 我认为 DrawText 没有在 GDI 路径文档中列出的原因是它在技术上是一个用户函数而不是 GDI 函数。但它在底层使用 GDI,所以它工作得很好。
  • 谢谢!一般来说,它有效。但质量令人作呕。任何想法如何使文本更具可读性?
  • @Iceman:没有使用普通 GDI 的简单想法。对于小文本,我使用了 James Poag 答案中的第二个项目符号,它在背景和文本之间提供了很好的分离。你能用一个纯色的矩形把文本后面的区域去掉吗?任何更花哨的东西都需要大量工作或使用更高级别的渲染系统,该系统在抚摸路径时会抗锯齿。
【解决方案3】:

以下是我的建议:

  1. 使用带有 PS_DASH 的 CreatePen 或 ExtCreatePen 创建具有虚线样式的自定义笔。
  2. 使用 DT_CALCRECT 和您想要的样式绘制文本,以查看文本的实际位置。
  3. SelectObject 将 HPEN 从 #1 放入您的 HDC
  4. 使用 MoveToEx 和 LineTo 根据在 #2 中检索到的矩形绘制框架的 4 条边(根据需要添加一些填充)。此处的示例代码:https://msdn.microsoft.com/en-us/library/windows/desktop/dd145182(v=vs.85).aspx

第 1 步发生在初始化时。每次绘画时都会执行第 2-4 步。

【讨论】:

    猜你喜欢
    • 2015-03-23
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多