最近在做项目时,需要实现在摄像机显示的图像上绘制指定的图案。就这样一个简单的功能花了三四天才彻底做出来,大部分时间都浪费在解决图像闪烁问题。于是整理了一下大概实现代码,用于记录成长过程和分享。
大概实现代码如下:
// 获取与窗口相关的HDC
HDC hdc = GetWindowDC(((HWND)m_hwnd));
/*如果直接在hdc上进行绘画时,很大概率上会发生视频录像中图像闪烁的问题。一开始我就是直接在此句柄上进行绘制,导致显示出来的数据一直在闪烁。*/
// 创建内存DC(创建一个与窗口矩形显示兼容的内存显示设备描述表)
HDC hMemDC = CreateCompatibleDC(hdc);
HDRAWDIB hdib =::DrawDibOpen();
// 用完记得最后调用 ::DrawDibClose(hdib);关闭
// 在hMemDC上画出需要的画面显示数据
int nRet=::DrawDibDraw(hdib,hMemDC,rc.left,rc.top,rc.right,rc.bottom,&(m_bmpInfo.bmiHeader),m_drawbuf,0,0,fixed_width,fixed_height,0);
// 这里的m_hwnd 窗口句柄,由上层传递
RECT rc;
GetClientRect(m_hwnd, &rc);
int nWidth = rc.right - rc.left;
int nHeight = rc.bottom - rc.top;
// 创建兼容性位图(用hdc创建一个与窗口矩形显示兼容的位图)
HBITMAP hMemBitmap = CreateCompatibleBitmap(hdc, nWidth , nHeight );
// 将位图hBitmap选入到内存显示设备的hMenDC中,只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
SelectObject(hMemDC, hMemBitmap);
// 进行绘图操作
// 设置输出方式(TRANSPARENT:使用透明的输出)
SetBkMode((hMemDC , TRANSPARENT);
// 计算字体高度与磅值
LOGFONT lFont;
memset(&lFont, 0, sizeof(LOGFONT));
// 设为16号字体
lFont.lfHeight = -MulDiv(16, GetDeviceCaps(hMemDC , LOGPIXELSY), 80);
lFont.lfWeight = FW_BOLD;
// 创建字体
HFONT hFont;
hFont = ::CreateFontIndirect(&lFont);
//选择字体
HGDIOBJ hOldFont = ::SelectObject(hMemDC , hFont);
// 设置颜色 这里设置为(0,0,0)黑色,其他颜色可自己指定
SetTextColor((hMemDC , RGB(0, 0, 0));
// 设置摄像机视频指定字符输出
std::string strText = “用于测试显示字符,图像是否闪烁”;
int nLen = (int)strText.size();
std::wstring wstr;
wstr.resize(nLen, L' ');
// CP_UTF8 utf_8显示
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)strText.c_str(), nLen, (LPWSTR)wstr.c_str(), nLen);
// 确定文字绘制区域
RECT rcDraw = { 0 };
rcDraw.left = 0; // 具体位置按自己实际需求进行填写
rcDraw.top = 0;
rcDraw.right = 200;
rcDraw.bottom = 150;
// 画指定数据 DT_LEFT左上角 DT_WORDBREAK超过指定宽度自动换行
DrawText(hMemDC, (LPCWSTR)wstr.c_str(), (int)strText.size(), &rcDraw, DT_LEFT | DT_WORDBREAK);
/// 最重要的一步
// 再将hMemDC画好的图案贴回到hdc上
BitBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, hMemDC, 0, 0, SRCCOPY);
// 清空
::SelectObject(hMemDC, hOldFont);
::DeleteObject(hFont);
hFont = NULL;
hOldFont = NULL;
// 图已经画出来了.删除位图
::DeleteObject(hMemBitmap);
// 删掉内存hMemDC
DeleteDC(hMemDC);
::ReleaseDC(m_hwnd, hdc);
不同环境实现时的代码一般都有差别,以上代码仅供参考。
参考资料的链接
获取HDC方法
实现双缓存
BitBlt()双缓冲解决图象闪烁
BitBlt参数含义