使用StretchBlt之前一定要用SetStretchBltMode(COLORONCOLOR)

来源:互联网 发布:为交换机端口分配vlan 编辑:程序博客网 时间:2024/05/07 18:21

近日要实现将缩小的位图保存在后台,以便在OnPaint刷新的时候仍然可以看到正确的图像,遂在lg_Bitmap类中添加了这样一个函数

    BOOL lg_Bitmap::LoadFromHDC(HDC hDC)
    
{
        
if(NULL == hDC)
            
return FALSE;
        BITMAP Bitmap;
        HBITMAP hBitmap 
= (HBITMAP)::GetCurrentObject(hDC,OBJ_BITMAP);
        
        ::GetObject(hBitmap,
sizeof(BITMAP),&Bitmap); 

        
if(Bitmap.bmHeight <= 0||Bitmap.bmWidth <= 0||Bitmap.bmWidthBytes <= 0)
            
return FALSE;

        BITMAPINFOHEADER
& bih = m_bmi.bmiHeader;
        ::ZeroMemory( 
&bih, sizeof( BITMAPINFOHEADER ));
        bih.biSize        
= sizeof( BITMAPINFOHEADER );
        bih.biWidth       
= Bitmap.bmWidth;
        bih.biHeight      
= Bitmap.bmHeight;
        bih.biCompression 
= BI_RGB;//BI_JPEG;//BI_JPEG
        bih.biPlanes      = 1;
        bih.biBitCount      
= 24;
        
        
int nLineDataSize = ((bih.biBitCount * Bitmap.bmWidth+31)/32)*4;
        bih.biWidth       
= nLineDataSize/(bih.biBitCount/8);//(width * nChannels * 8 +31) / 8;
        int nLineCopySize = bih.biWidth*(bih.biBitCount/8);
        DWORD dwWholeSize 
= nLineDataSize * abs(bih.biHeight);
        BYTE
* pTemp = new BYTE[dwWholeSize];
        memset(pTemp,
0,dwWholeSize);

        
int nLine = ::GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,
            pTemp,
&m_bmi, DIB_RGB_COLORS);

        
if(nLine <= 0)
        
{
            delete [] pTemp;
            
return FALSE;
        }

        BOOL bSuccess
=CreateBitmapIndirect(&m_bmi, pTemp);
        delete [] pTemp;
        
return bSuccess;
    }

然后在外部如此调用

        CDC * pScreenDC = new CDC;
        pScreenDC
->CreateCompatibleDC(pDC);
        CBitmap TempBitmap;
        TempBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
        CBitmap
* pOldScreenDC = NULL;
        pOldScreenDC 
= (CBitmap*)pScreenDC->SelectObject(&TempBitmap);
        pScreenDC->StretchBlt(0,0,rect.Width(),rect.Height(),pMemDC,0,0,BIT.bmWidth,BIT.bmHeight,SRCCOPY);
        DrawTxtInDC(pScreenDC,
5,15,topinfo,strPosition,rect.Height());
        
if(g_ScreenBitmap.LoadFromHDC(pScreenDC->GetSafeHdc()))
        
{
            m_bHaveDataInBuffer 
= TRUE;
        }
else{
            m_bHaveDataInBuffer 
= FALSE;
        }

        pScreenDC
->SelectObject(pOldScreenDC);
        delete pScreenDC;

再然后界面显示了一张这样的图

我就郁闷了,好好的图咋整这样了呢?开始找原因
由于位图类中没有提供保存位图的功能,遂再增加两个函数
1,保存lg_Bitmap自身的图 2,保存指定LPBITMAPINFOHEADER,和缓冲的图

    //不支持调色板
    BOOL lg_Bitmap::SaveThis(LPCTSTR fn)
    
{
        BITMAP bmp;
        GetBitmap(
&bmp);
        
return Save(&m_bmi.bmiHeader,bmp.bmBits,fn);
    }

    BOOL lg_Bitmap::Save(LPBITMAPINFOHEADER lpIn,LPVOID lpBuf,LPCTSTR fn)
    
{
        
//位图文件大小 , 写入文件字节数
        DWORD dwBmBitsSize,dwDIBSize;

        
//位图文件头结构
        BITMAPFILEHEADER   bmfHdr;    
    
        
//指向位图信息头结构
        LPBITMAPINFOHEADER lpbi;

        dwBmBitsSize 
= ((lpIn->biWidth *lpIn->biBitCount+31)/32)* 4*lpIn->biHeight;

        
//为位图内容分配内存
        HANDLE hDib  = GlobalAlloc(GHND,dwBmBitsSize+sizeof(BITMAPINFOHEADER));
        lpbi 
= (LPBITMAPINFOHEADER)GlobalLock(hDib);
        memcpy(lpbi,lpIn,
sizeof(BITMAPINFOHEADER));

        memcpy((LPSTR)lpbi 
+ sizeof(BITMAPINFOHEADER),lpBuf,dwBmBitsSize);

        
// 设置位图文件头
        bmfHdr.bfType = 0x4D42;  // "BM"
        dwDIBSize    = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmBitsSize;  
        bmfHdr.bfSize 
= dwDIBSize;
        bmfHdr.bfReserved1 
= 0;
        bmfHdr.bfReserved2 
= 0;
        bmfHdr.bfOffBits 
= (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
        
if(!SaveDataToFile((LPSTR)&bmfHdr,sizeof(BITMAPFILEHEADER),fn,TRUE))
        
{
            GlobalUnlock(hDib);
            GlobalFree(hDib);
            
return FALSE;
        }

        
if(!SaveDataToFile((LPSTR)lpbi,dwDIBSize,fn))
        
{
            GlobalUnlock(hDib);
            GlobalFree(hDib);
            
return FALSE;
        }


        GlobalUnlock(hDib);
        GlobalFree(hDib);
        
return TRUE;
    }

 

然后在lg_Bitmap::LoadFromHDC(HDC hDC)的结尾加入这么一段

        lg_TimeString Tsing;
        
string sPath = Tsing.Format("e:\抓图\%N%Y%R%S%F%M%H.bmp");
        CreateAllDirectory(sPath.c_str());
//        SaveThis(sPath.c_str());
        Save(&bih,pTemp,sPath.c_str());

结果无论是lg_Bitmap自身还是外部传来的位图无一例外的变成了上面那个图的样子
..............思考中,无意中在google上看到一句话,在使用StretchBlt缩小位图的时候要SetStretchBltMode(COLORONCOLOR).......我晕,管他先试试。

        CDC * pScreenDC = new CDC;
        pScreenDC
->CreateCompatibleDC(pDC);
        CBitmap TempBitmap;
        TempBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
        CBitmap
* pOldScreenDC = NULL;
        pOldScreenDC 
= (CBitmap*)pScreenDC->SelectObject(&TempBitmap);
        pScreenDC
->SetStretchBltMode(COLORONCOLOR);
        pScreenDC
->StretchBlt(0,0,rect.Width(),rect.Height(),pMemDC,0,0,BIT.bmWidth,BIT.bmHeight,SRCCOPY);
        DrawTxtInDC(pScreenDC,
5,15,topinfo,strPosition,rect.Height());
        
if(g_ScreenBitmap.LoadFromHDC(pScreenDC->GetSafeHdc()))
        
{
            m_bHaveDataInBuffer 
= TRUE;
        }
else{
            m_bHaveDataInBuffer 
= FALSE;
        }

        pScreenDC
->SelectObject(pOldScreenDC);
        delete pScreenDC;

结果

原创粉丝点击