GDI -- 將灰度圖數據畫到控件上

實現功能

  1. 將灰度圖內存數據畫到控件上
  2. 原始灰度圖的寬高與控件寬高不相同
  3. 在畫到控件上之前要在原始的灰度圖上做一些效果,如疊加文字、畫效果圖形等

上代碼

void ShowFrameOnCtl(HWND hWnd, unsigned char* frame, int w, int h)
{
	HDC hdcPicControl;

	// GetDC() need to be ReleaseDC
	hdcPicControl = ::GetDC(hWnd);

	RECT rcPic;
	::GetClientRect(hWnd, &rcPic);

	int nWidth = rcPic.right - rcPic.left;
	int nHeight = rcPic.bottom - rcPic.top;

	HDC hCompatibleDC = CreateCompatibleDC(hdcPicControl);
	HBITMAP hCompatibleBitmap = CreateCompatibleBitmap(hdcPicControl, w, h);
	HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, hCompatibleBitmap);

	// 灰度圖
	BITMAPINFOHEADER BitmapInfo;
	BITMAPINFO *_BitmapInfo = (BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER) * 256 * sizeof(RGBQUAD)];
	memset(_BitmapInfo, 0, sizeof(BITMAPINFOHEADER));

	BitmapInfo.biSize = 40;
	BitmapInfo.biPlanes = 1;
	BitmapInfo.biBitCount = 8;
	BitmapInfo.biClrImportant = 0;
	BitmapInfo.biCompression = BI_RGB;
	BitmapInfo.biXPelsPerMeter = 0;
	BitmapInfo.biYPelsPerMeter = 0;
	BitmapInfo.biClrUsed = 256;
	BitmapInfo.biClrImportant = 0;
	BitmapInfo.biWidth = 0;
	BitmapInfo.biHeight = 0;

	/*把BMP位圖信息頭中的數據讀取到位圖信息結構中去.*/
	memcpy(_BitmapInfo, &BitmapInfo, sizeof(BITMAPINFOHEADER));

	RGBQUAD *rgb = (RGBQUAD*)((BYTE*)_BitmapInfo + sizeof(BITMAPINFOHEADER));
	for (int i = 0; i < 256; ++i) {
		rgb[i].rgbBlue = rgb[i].rgbGreen = rgb[i].rgbRed = i;
	}

	_BitmapInfo->bmiHeader.biWidth = w;
	_BitmapInfo->bmiHeader.biHeight = -1 * h;
	_BitmapInfo->bmiHeader.biSizeImage = 0;
	_BitmapInfo->bmiHeader.biBitCount = 8;
	_BitmapInfo->bmiHeader.biClrUsed = 256;

	SetStretchBltMode(hCompatibleDC, COLORONCOLOR);
	StretchDIBits(hCompatibleDC,
		0, 0, w, h,
		0, 0, w, h,
		frame, _BitmapInfo, DIB_RGB_COLORS, SRCCOPY);

	//在內存DC上畫一些效果
	if (!m_disableDraw)
		drawView(hCompatibleDC, w, h);

	delete _BitmapInfo;

	SetStretchBltMode(hdcPicControl, COLORONCOLOR);
	::StretchBlt(hdcPicControl, 0, 0, nWidth, nHeight, hCompatibleDC, 0, 0, w, h, SRCCOPY);

	SelectObject(hCompatibleDC, hOldBitmap);
	DeleteObject(hCompatibleBitmap);
	DeleteDC(hCompatibleDC);
	// ReleaseDC of hdcPicControl
	ReleaseDC(hWnd, hdcPicControl);
}

小結

創建內存位圖
HBITMAP CreateCompatibleBitmap(HDC hdc,int nWidth,int nHeight)

nWidth 和 nHeight不一定要和hdc的大小一樣, 這樣可以讓創建的位置和原始圖像一致,最後內存DC拷貝到原始DC時,縮放一下即可

背景知識

什麼是DC

device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing operations. The remainder of this section is divided into the following three areas.

這是微軟官方的解釋,翻譯一下:

DC全稱Device Contexts, 意爲設備上下文,它是一個定義了一系列圖形對象及其屬性發生的數據結構,其他也包括一些影響顯示的圖形模式。 圖形對象包括畫筆(畫直線)、畫刷(填充)、位圖(拷貝或滾動屏幕的其他部分)、調色板(定義了一系列顏色)、裁剪區、路徑。

另外,設備上下文是設備無關的,DC主要是給用戶一致的繪圖體驗,它是用戶與真實設備驅動之間一個橋樑,用來屏蔽設備驅動等底層細節

雙緩衝

雙緩衝是一種方法,它可以用來避免畫圖閃爍的問題。如果直接在畫布上畫圖,每次都要先擦除再繪製,這一過程需要時間,如果顯示的刷新頻率很快或繪製過程很慢(比較CPU性能差),就會讓用戶看到這一中間過程,造成閃爍現象。

Win32中雙緩衝的原理是先創建一個內存DC,畫圖繪製在內存DC上,繪製好後將內存DC直接拷貝到原始DC上,這樣就避免了閃爍。


就醬~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章