使用 GDI (C++) 绘制带轮廓的文本

DrawText with outline using GDI (C++)

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

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带轮廓?例如,白色文本带有黑色轮廓。

两种方法:

  • 将文本绘制成黑色,但稍微放大 2 个像素(祝你好运)和 偏移 (-1,-1) 然后通常在中间是白色。

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

对于 GDI,您可以使用 BeginPath、DrawText、EndPath,然后使用 StrokeAndFillPath,只要您使用 "outline" 字体(如 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 文本那样清晰。在更大的尺寸下,这不是一个大问题。

以下是我的推荐:

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

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