关于MFC实现截屏相关有关问题
求助:关于MFC实现截屏相关问题
小弟新人,初来乍到,公司给的项目任务中有一个截屏的功能,基于MFC截屏。在网络上有不少类似的源代码,但是都有一个很巨大的问题,就是截取的图片过于巨大。最经典的代码就是下面的代码CDC *pDC;//屏幕DC
pDC = CDC::FromHandle(reinterpret_cast<HDC>(::GetDC(NULL)));//获取当前整个屏幕DC
int BitPerPixel = pDC->GetDeviceCaps(BITSPIXEL);//获得颜色模式
int Width = pDC->GetDeviceCaps(HORZRES);
int Height = pDC->GetDeviceCaps(VERTRES);
printf("当前屏幕色彩模式为%d位色彩\n", BitPerPixel);
printf("屏幕宽度:%d\n", Width);
printf("屏幕高度:%d\n", Height);
CDC memDC;//内存DC
memDC.CreateCompatibleDC(pDC);
CBitmap memBitmap, *oldmemBitmap;//建立和屏幕兼容的bitmap
memBitmap.CreateCompatibleBitmap(pDC, Width, Height);
oldmemBitmap = memDC.SelectObject(&memBitmap);//将memBitmap选入内存DC
memDC.BitBlt(0, 0, Width, Height, pDC, 0, 0, SRCCOPY);//复制屏幕图像到内存DC
//以下代码保存memDC中的位图到文件
BITMAP bmp;
memBitmap.GetBitmap(&bmp);//获得位图信息
FILE *fp = fopen(filename, "w+b");
BITMAPINFOHEADER bih = {0};//位图信息头
bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小
bih.biCompression = BI_RGB;
bih.biHeight = bmp.bmHeight;//高度
bih.biPlanes = 1;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小
bih.biWidth = bmp.bmWidth;//宽度
BITMAPFILEHEADER bfh = {0};//位图文件头
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//到位图数据的偏移量
bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;//文件总的大小
bfh.bfType = (WORD)0x4d42;
fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头
fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//写入位图信息头
byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight];//申请内存保存位图数据
GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, 0, Height, p,
(LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据
fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);//写入位图数据
delete [] p;
fclose(fp);
memDC.SelectObject(oldmemBitmap);
//AfxMessageBox(_T("保存照片成功!"));
return TRUE;
但用这个代码截取的屏幕图片大小 一张1366 * 768 的就高达4MB。自己用键盘上的截屏按键截取的图片同样的分辨率下只有200多KB,为何会有如此巨大的差异。求高人指点,如何优化代码,减小图片的体积,涉及到网络上传4MB大小的图片十分耽误时间,求解决方案。不胜感激
------解决思路----------------------
你可以直接将位图句柄保存为png或者jpg的图片,这样会小很多,使用GDI+来处理,给你一段代码参考一下:
小弟新人,初来乍到,公司给的项目任务中有一个截屏的功能,基于MFC截屏。在网络上有不少类似的源代码,但是都有一个很巨大的问题,就是截取的图片过于巨大。最经典的代码就是下面的代码CDC *pDC;//屏幕DC
pDC = CDC::FromHandle(reinterpret_cast<HDC>(::GetDC(NULL)));//获取当前整个屏幕DC
int BitPerPixel = pDC->GetDeviceCaps(BITSPIXEL);//获得颜色模式
int Width = pDC->GetDeviceCaps(HORZRES);
int Height = pDC->GetDeviceCaps(VERTRES);
printf("当前屏幕色彩模式为%d位色彩\n", BitPerPixel);
printf("屏幕宽度:%d\n", Width);
printf("屏幕高度:%d\n", Height);
CDC memDC;//内存DC
memDC.CreateCompatibleDC(pDC);
CBitmap memBitmap, *oldmemBitmap;//建立和屏幕兼容的bitmap
memBitmap.CreateCompatibleBitmap(pDC, Width, Height);
oldmemBitmap = memDC.SelectObject(&memBitmap);//将memBitmap选入内存DC
memDC.BitBlt(0, 0, Width, Height, pDC, 0, 0, SRCCOPY);//复制屏幕图像到内存DC
//以下代码保存memDC中的位图到文件
BITMAP bmp;
memBitmap.GetBitmap(&bmp);//获得位图信息
FILE *fp = fopen(filename, "w+b");
BITMAPINFOHEADER bih = {0};//位图信息头
bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小
bih.biCompression = BI_RGB;
bih.biHeight = bmp.bmHeight;//高度
bih.biPlanes = 1;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小
bih.biWidth = bmp.bmWidth;//宽度
BITMAPFILEHEADER bfh = {0};//位图文件头
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//到位图数据的偏移量
bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;//文件总的大小
bfh.bfType = (WORD)0x4d42;
fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头
fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//写入位图信息头
byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight];//申请内存保存位图数据
GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, 0, Height, p,
(LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据
fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);//写入位图数据
delete [] p;
fclose(fp);
memDC.SelectObject(oldmemBitmap);
//AfxMessageBox(_T("保存照片成功!"));
return TRUE;
但用这个代码截取的屏幕图片大小 一张1366 * 768 的就高达4MB。自己用键盘上的截屏按键截取的图片同样的分辨率下只有200多KB,为何会有如此巨大的差异。求高人指点,如何优化代码,减小图片的体积,涉及到网络上传4MB大小的图片十分耽误时间,求解决方案。不胜感激
------解决思路----------------------
你可以直接将位图句柄保存为png或者jpg的图片,这样会小很多,使用GDI+来处理,给你一段代码参考一下:
// 使用gdi+将HBITMAP位图句柄图片资源保存成图片文件,图片文件的类型包括bmp、jpg、png、gif和tiff
// 根据lpfilename中包含的扩展名来判断是保存到哪个类型的文件中
BOOL CCatchScreenDlg::SaveHBitmapToFile( HBITMAP hBmp, LPCTSTR lpfilename )
{
if ( hBmp == NULL
------解决思路----------------------
lpfilename == NULL )
{
WriteScreenCatchLog( "[CCatchScreenDlg::SaveHBitmapToFile]hBmp或lpfilename为空,return", m_strLogPath );
return FALSE;
}
Bitmap *pSrcBmp = Bitmap::FromHBITMAP( hBmp, NULL );
if ( pSrcBmp == NULL )
{
WriteScreenCatchLog( "[CCatchScreenDlg::SaveHBitmapToFile]Bitmap::FromHBITMAP失败,return", m_strLogPath );
return FALSE;
}
// 获取文件的扩展名
CString strExtName = _T("");
CString strFilePatch = lpfilename;
int nPos = strFilePatch.ReverseFind(_T('.'));
if ( nPos != -1)
{
strExtName = strFilePatch.Right( strFilePatch.GetLength() - nPos - 1 );
}
// GDI+中有五种编码:bmp、jpeg、gif、tiff和png,下面根据
// 文件名的扩展部分来获取对应的编码CLSID
CLSID encoderClsid;
if ( strExtName == _T("bmp") )
{
GetEncoderClsid( L"image/bmp", &encoderClsid );
}
else if ( strExtName == _T("jpg") )
{
GetEncoderClsid( L"image/jpeg", &encoderClsid );
}
else if ( strExtName == _T("png") )
{
GetEncoderClsid( L"image/png", &encoderClsid );
}
else if ( strExtName == _T("gif") )
{
GetEncoderClsid( L"image/gif", &encoderClsid );
}
else if ( strExtName == _T("tiff") )
{
GetEncoderClsid( L"image/tiff", &encoderClsid );
}
else // 没有指定类型的扩展名,则默认使用png
{
GetEncoderClsid( L"image/png", &encoderClsid );
}
LPWSTR lpWStrFileName = NULL; // 注意:Bitmap::Save接口第一个参数是宽字节参数
#ifdef _UNICODE
lpWStrFileName = lpfilename; // 如果是_UNICODE模式,直接使用
#else
WCHAR wchFileName[MAX_PATH*2] = {0};
MultiByteToWideChar( CP_ACP, 0, lpfilename, -1, wchFileName, strlen(lpfilename)+1 ); // 将窄字符转化为宽字符
lpWStrFileName = wchFileName;
#endif
Status ret = pSrcBmp->Save( lpWStrFileName, &encoderClsid );
if ( ret != Ok )
{
WriteScreenCatchLog( "[CCatchScreenDlg::SaveHBitmapToFile]Bitmap::Save失败,return", m_strLogPath );
// 释放内存
delete pSrcBmp;
return FALSE;
}
// 释放内存
delete pSrcBmp;
return TRUE;
}
// 获取jpeg等编码Clsid
int CCatchScreenDlg::GetEncoderClsid( const WCHAR* format, CLSID* pClsid )
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize( &num, &size );
if( size == 0 )
{
return -1;
}
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if( pImageCodecInfo == NULL )
{
return -1;
}
GetImageEncoders( num, size, pImageCodecInfo );
for( UINT j = 0; j < num; ++j )
{
if( wcscmp( pImageCodecInfo[j].MimeType, format ) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free( pImageCodecInfo );
return -1;
}