国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

windows抓屏(截屏)實(shí)現(xiàn)方法

2019-11-08 01:26:43
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

         在windows系統(tǒng)中,抓取當(dāng)前桌面的屏幕有很多方法,比較常用的是GDI和mirror兩種方式,除此以外,利用ddraw和dxgi(windows7以上系統(tǒng)支持)方式也可以抓取屏幕。由于mirror的方式牽扯到驅(qū)動(dòng),并且也不是所有系統(tǒng)都支持,本文不會(huì)介紹這種抓屏方式,這里將著重介紹GDI, DDRAW和DXGI這三種抓屏方式,并給出其相應(yīng)的實(shí)現(xiàn)代碼。

        GDI抓屏

        這種方式比較通用,所有的windows版本都支持此方式抓屏,而且不依賴其他API,僅僅使用user32中的API即可完成抓屏;但是這種抓屏方式相對(duì)比較慢,抓取一幀1080p的桌面需要5~8ms左右的時(shí)間。單純的從抓屏來(lái)說(shuō),這個(gè)時(shí)間還是可以接受的,但是抓屏后往往需要進(jìn)行很多圖像處理,所以這個(gè)用時(shí)就顯得不那么友好了。而且在Vista以后的系統(tǒng)上,如果啟用Aero特效的話,抓取一幀的用時(shí)會(huì)增加到300~500ms,基本上屬于不可用的級(jí)別。

       下面給出實(shí)現(xiàn)代碼:

HDC               m_hMemDC, m_hRootDC;HBITMAP           m_hBitmapMem;DEVMODE           m_origDevMode;BITMAPINFO        m_bitmapInfo;void             *m_pvBits;int               m_iWidth = 1920,m_iHeight = 1080;BOOL InitBitmapInfo(void){ 	if (m_hRootDC)	{		return FALSE;	}	m_hRootDC = CreateDC(("DISPLAY"), NULL, NULL, NULL);	if (!m_hRootDC)	{		return FALSE;	}	m_hMemDC = CreateCompatibleDC(m_hRootDC);        if (!m_hMemDC)	{               return FALSE;        }        m_hBitmapMem = CreateCompatibleBitmap(m_hRootDC, m_iWidth, m_iHeight);        if (!m_hBitmapMem)	{            return FALSE;        }        return TRUE;}BOOL CreateDIBBuffers(void){	m_bitmapInfo.bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);        m_bitmapInfo.bmiHeader.biBitCount = 0;        if (GetDIBits(m_hMemDC, m_hBitmapMem, 0, 1, NULL, &m_bitmapInfo, DIB_RGB_COLORS) == 0)	{               return FALSE;        }	m_bitmapInfo.bmiHeader.biComPRession = BI_RGB;	m_bitmapInfo.bmiHeader.biHeight      = -abs(m_bitmapInfo.bmiHeader.biHeight);  // 因?yàn)樽ト〉膱D片是上下顛倒的,所以這里需要將高度顛倒一下        HBITMAP hBitmapTmp = CreateDIBSection(m_hMemDC, &m_bitmapInfo, DIB_RGB_COLORS, &m_pvBits, NULL, 0);        if (!hBitmapTmp)	{               ("Can not use fast blit!/n");	}        if (m_hBitmapMem != NULL)	{              DeleteObject(m_hBitmapMem);              m_hBitmapMem = NULL;        }	m_hBitmapMem = hBitmapTmp;        return TRUE;}void  ByteAlign(RECT &rect){	int nWidth = rect.right - rect.left;	int nHeight = rect.bottom - rect.top;	//	// 對(duì)齊4字節(jié)邊界	// 因?yàn)镚DI的原因,分辨率必須要是4字節(jié)的邊界,否則抓出來(lái)的圖像重新渲染的話,	// 會(huì)出現(xiàn)花屏現(xiàn)象,這里處理的目的就是為了保證是4字節(jié)的邊界。——yshen on 2012-11-25	//	int nMod = nWidth % 4;	if (nMod)	{		rect.left  += (nMod / 2);		rect.right -= (nMod / 2);	}	nMod = nHeight % 4;	if (nMod)	{		rect.top    += (nMod / 2);		rect.bottom -= (nMod / 2);	}}int CaptureScreen(const RECT &rect){       	ByteAlign(rect);	// 檢測(cè)和啟動(dòng)時(shí)的分辨率是否一致,如果不一致,則停止抓屏	INT nWidth  = GetSystemMetrics(SM_CXSCREEN);        INT nHeight = GetSystemMetrics(SM_CYSCREEN);	if ((m_iWidth != nWidth) && (m_iHeight != nHeight))	{		return -1;	}	GdiFlush();	HBITMAP hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmapMem);	if (hOldBitmap)	{		BitBlt(m_hMemDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, m_hRootDC, rect.left, rect.top, SRCCOPY | CAPTUREBLT);		SelectObject(m_hMemDC, hOldBitmap);	}	return 0;}BOOL Init(void){	if (!InitBitmapInfo())	{            return FALSE;        }        if (!CreateDIBBuffers())	{            return FALSE;        }    return TRUE;}

調(diào)用示例:

  // 初始化抓屏     init();     // 抓取一幀     RECT rect(0, 0, 1920, 1080);    CaptureScreen(rect);

   DDRAW抓屏

    這種方式抓屏速度比GDI要快一些,抓取一幀圖像大概需要4~5ms左右,但是缺點(diǎn)也和GDI一樣,如果啟用了特效,速度也非常慢,基本也在400ms以上。

    實(shí)現(xiàn)代碼:

LPDIRECTDRAW        m_lpDDraw;LPDIRECTDRAWSURFACE m_lpDDSPrime;LPDIRECTDRAWSURFACE m_lpDDSBack;DDSURFACEDESC       m_DDSdesc;BOOL Init(){	HMODULE hDll = LoadLibrary("ddraw.dll");	if (hDll == NULL)	{		("無(wú)法載入ddraw.dll/n");		return FALSE;	}	// 載入ddraw的導(dǎo)入函數(shù)	PFN_DirectDrawCreate DirectDrawCreateFunc = (PFN_DirectDrawCreate)GetProcAddress(hDll, "DirectDrawCreate");	if (DirectDrawCreateFunc == NULL)	{		("無(wú)法找到訪問(wèn)點(diǎn):DirectDrawCreate/n");		return FALSE;	}	HRESULT hr = DirectDrawCreateFunc(NULL, &m_lpDDraw, NULL);	if (FAILED(hr))	{		("DirectDrawCreate失敗/n");		return FALSE;	}	hr = m_lpDDraw->SetCoOperativeLevel(NULL, DDSCL_NORMAL);	if (FAILED(hr))	{		("SetCooperativeLevel失敗/n");		return FALSE; 	}	DDSURFACEDESC DDSdesc;	ZeroMemory(&DDSdesc, sizeof(DDSdesc));	DDSdesc.dwSize         = sizeof(DDSdesc);	DDSdesc.dwFlags        = DDSD_CAPS;	DDSdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;	hr = m_lpDDraw->CreateSurface(&DDSdesc, &m_lpDDSPrime, NULL);	if (FAILED(hr))	{		("CreateSurface 主表面失敗/n");		return FALSE; 	}	ZeroMemory(&DDSdesc, sizeof(DDSdesc));	DDSdesc.dwSize  = sizeof(DDSdesc);	DDSdesc.dwFlags = DDSD_ALL;	hr = m_lpDDSPrime->GetSurfaceDesc(&DDSdesc);	if (FAILED(hr))	{		("GetSurfaceDesc失敗/n");		return FALSE;	}	// 備份描述信息	memcpy(&m_DDSdesc, &DDSdesc, sizeof(DDSdesc));	DDSdesc.dwFlags        = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; 	DDSdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;	hr = m_lpDDraw->CreateSurface(&DDSdesc, &m_lpDDSBack, 0);	if (FAILED(hr))	{		("CreateSurface 后備表面失敗/n");		return FALSE;	}	return TRUE;}BOOL CaptureImage(RECT &rect, void *pData, INT &nLen){	if (m_lpDDSBack == NULL)	{		("DDraw對(duì)象未初始化/n");		return FALSE;	}	HRESULT hr = m_lpDDSBack->BltFast(rect.left, rect.top, m_lpDDSPrime, &rect, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);	if (FAILED(hr))	{		("BltFast失敗/n");		return FALSE;	}	DDSURFACEDESC surfDesc;	ZeroMemory(&surfDesc, sizeof(surfDesc)); 	surfDesc.dwSize = sizeof(surfDesc);	hr = m_lpDDSBack->Lock(&rect, &surfDesc, DDLOCK_READONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR , NULL);	if (FAILED(hr))	{		("Lock失敗/n");		return FALSE;	}	// 這里拷貝的是32位數(shù)據(jù)	memcpy(pBuf, (BYTE*)surfDesc.lpSurface, surfDesc.dwWidth * surfDesc.dwHeight * surfDesc.ddpfPixelFormat.dwRGBBitCount / 8);	 m_lpDDSBack->Unlock(surfDesc.lpSurface);	return TRUE;}

  DXGI抓屏

     這種抓屏方式,速度非常快,通常一幀圖像能夠在2~3ms內(nèi)完成,而且即使啟用了Aero特效,抓屏效率也一樣。尤其在windows10以后的系統(tǒng)上,當(dāng)桌面沒(méi)有變化時(shí),你是抓取不到任何圖像的,只有在桌面有變化時(shí),你才能抓取到圖像。這會(huì)帶來(lái)更高的抓屏效率和更少的系統(tǒng)開(kāi)銷(xiāo)。當(dāng)然,它也不是完美的,它只能在vista以上的系統(tǒng)上才可以使用,老舊的xp是不支持這種新技術(shù)的。

     實(shí)現(xiàn)代碼:

ID3D11Device           *m_hDevice;ID3D11DeviceContext    *m_hContext;IDXGIOutputDuplication *m_hDeskDupl;DXGI_OUTPUT_DESC        m_dxgiOutDesc;BOOL Init(){	HRESULT hr = S_OK;	// Driver types supported	D3D_DRIVER_TYPE DriverTypes[] =	{		D3D_DRIVER_TYPE_HARDWARE,		D3D_DRIVER_TYPE_WARP,		D3D_DRIVER_TYPE_REFERENCE,	};	UINT NumDriverTypes = ARRAYSIZE(DriverTypes);	// Feature levels supported	D3D_FEATURE_LEVEL FeatureLevels[] =	{		D3D_FEATURE_LEVEL_11_0,		D3D_FEATURE_LEVEL_10_1,		D3D_FEATURE_LEVEL_10_0,		D3D_FEATURE_LEVEL_9_1	};	UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);	D3D_FEATURE_LEVEL FeatureLevel;	//	// Create D3D device	//	for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)	{		hr = D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, 0, FeatureLevels, NumFeatureLevels, D3D11_SDK_VERSION, &m_hDevice, &FeatureLevel, &m_hContext);		if (SUCCEEDED(hr))		{			break;		}	}	if (FAILED(hr))	{		return FALSE;	}	//	// Get DXGI device	//	IDXGIDevice *hDxgiDevice = NULL;	hr = m_hDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&hDxgiDevice));	if (FAILED(hr))	{		return FALSE;	}	//	// Get DXGI adapter	//	IDXGIAdapter *hDxgiAdapter = NULL;	hr = hDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&hDxgiAdapter));	RESET_OBJECT(hDxgiDevice);	if (FAILED(hr))	{		return FALSE;	}	//	// Get output	//	INT nOutput = 0;	IDXGIOutput *hDxgiOutput = NULL;	hr = hDxgiAdapter->EnumOutputs(nOutput, &hDxgiOutput);	RESET_OBJECT(hDxgiAdapter);	if (FAILED(hr))	{		return FALSE;	}	//	// get output description struct	//	hDxgiOutput->GetDesc(&m_dxgiOutDesc);		//	// QI for Output 1	//	IDXGIOutput1 *hDxgiOutput1 = NULL;	hr = hDxgiOutput->QueryInterface(__uuidof(hDxgiOutput1), reinterpret_cast<void**>(&hDxgiOutput1));	RESET_OBJECT(hDxgiOutput);	if (FAILED(hr))	{		return FALSE;	}	//	// Create desktop duplication	//	hr = hDxgiOutput1->DuplicateOutput(m_hDevice, &m_hDeskDupl);	RESET_OBJECT(hDxgiOutput1);	if (FAILED(hr))	{		return FALSE;	}	return TRUE;}BOOL AttatchToThread(VOID){		HDESK hCurrentDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);	if (!hCurrentDesktop)	{		return FALSE;	}	// Attach desktop to this thread	BOOL bDesktopAttached = SetThreadDesktop(hCurrentDesktop);	CloseDesktop(hCurrentDesktop);	hCurrentDesktop = NULL;	return bDesktopAttached;}BOOL VideoDXGICaptor::QueryFrame(void *pImgData, INT &nImgSize){	if (!AttatchToThread())	{		return FALSE;	}	nImgSize = 0;	IDXGIResource *hDesktopResource = NULL;	DXGI_OUTDUPL_FRAME_INFO FrameInfo;	HRESULT hr = m_hDeskDupl->AcquireNextFrame(500, &FrameInfo, &hDesktopResource);	if (FAILED(hr))	{		//		// 在一些win10的系統(tǒng)上,如果桌面沒(méi)有變化的情況下,		// 這里會(huì)發(fā)生超時(shí)現(xiàn)象,但是這并不是發(fā)生了錯(cuò)誤,而是系統(tǒng)優(yōu)化了刷新動(dòng)作導(dǎo)致的。		// 所以,這里沒(méi)必要返回FALSE,返回不帶任何數(shù)據(jù)的TRUE即可		//		return TRUE;	}	//	// query next frame staging buffer	//	ID3D11Texture2D *hAcquiredDesktopImage = NULL;	hr = hDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&hAcquiredDesktopImage));	RESET_OBJECT(hDesktopResource);	if (FAILED(hr))	{		return FALSE;	}	//	// copy old description	//	D3D11_TEXTURE2D_DESC frameDescriptor;	hAcquiredDesktopImage->GetDesc(&frameDescriptor);	//	// create a new staging buffer for fill frame image	//	ID3D11Texture2D *hNewDesktopImage = NULL;	frameDescriptor.Usage = D3D11_USAGE_STAGING;	frameDescriptor.CPUaccessFlags = D3D11_CPU_ACCESS_READ;	frameDescriptor.BindFlags = 0;	frameDescriptor.MiscFlags = 0;	frameDescriptor.MipLevels = 1;	frameDescriptor.ArraySize = 1;	frameDescriptor.SampleDesc.Count = 1;	hr = m_hDevice->CreateTexture2D(&frameDescriptor, NULL, &hNewDesktopImage);	if (FAILED(hr))	{		RESET_OBJECT(hAcquiredDesktopImage);		m_hDeskDupl->ReleaseFrame();		return FALSE;	}	//	// copy next staging buffer to new staging buffer	//	m_hContext->CopyResource(hNewDesktopImage, hAcquiredDesktopImage);	RESET_OBJECT(hAcquiredDesktopImage);	m_hDeskDupl->ReleaseFrame();	//	// create staging buffer for map bits	//	IDXGISurface *hStagingSurf = NULL;	hr = hNewDesktopImage->QueryInterface(__uuidof(IDXGISurface), (void **)(&hStagingSurf));	RESET_OBJECT(hNewDesktopImage);	if (FAILED(hr))	{		return FALSE;	}	//	// copy bits to user space	//	DXGI_MAPPED_RECT mappedRect;	hr = hStagingSurf->Map(&mappedRect, DXGI_MAP_READ);	if (SUCCEEDED(hr))	{		nImgSize = GetWidth() * GetHeight() * 3;		PrepareBGR24From32(mappedRect.pBits, (BYTE*)pImgData, m_dxgiOutDesc.DesktopCoordinates);		hStagingSurf->Unmap();	}	RESET_OBJECT(hStagingSurf);	return SUCCEEDED(hr);}DXGI只能使用vs2012以上的IDE才可以編譯。

         


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 蒲城县| 辛集市| 深泽县| 平度市| 凌云县| 齐齐哈尔市| 来宾市| 卢龙县| 双鸭山市| 高碑店市| 乐业县| 陇川县| 屏东市| 陇西县| 沁源县| 凤山县| 客服| 贺州市| 军事| 汝南县| 长阳| 平定县| 大港区| 鄂州市| 桂平市| 曲松县| 吕梁市| 阜宁县| 陈巴尔虎旗| 视频| 镶黄旗| 巫溪县| 万年县| 抚远县| 农安县| 双江| 桃源县| 贵州省| 同德县| 改则县| 志丹县|