关于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+来处理,给你一段代码参考一下:

// 使用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;     
}