MFC转换处理指针和DIB转换为DDB

时间:2016-06-27 03:27:52

标签: c++ mfc

我正在尝试通过硬编码像素值数组来创建位图,将此像素数组转换为DIB,然后将此DIB转换为DDB。我找到了两个在互联网上转换CreateBitmapFromPixels和DIBToDDB的函数。我的问题是该程序将在第244行崩溃。我发现,在第243行,lpbi不会从hDIB中检索信息。然后我在第229行和第230行添加了代码,看看在创建BITMAPINFO结构的函数中做同样的事情会有所帮助。仍然没有从HBITMAP获得任何东西。我想知道将句柄转换为指针是否有什么问题,它做了什么,还有其他方法可以将HBITMAPINFOHEADER从句柄转移到DIB,这样我就可以解决问题了。

 HBITMAP ColorChange2Dlg::CreateBitmapFromPixels( HDC hDC,
     UINT uWidth, UINT uHeight, UINT uBitsPerPixel, LPVOID pBits)
{
    if(uBitsPerPixel < 8) // NOT IMPLEMENTED YET
        return NULL;

    if(uBitsPerPixel == 8)
        return Create8bppBitmap(hDC, uWidth, uHeight, pBits);

    HBITMAP hBitmap = 0;
    if ( !uWidth || !uHeight || !uBitsPerPixel )
        return hBitmap;
    LONG lBmpSize = uWidth * uHeight * (uBitsPerPixel/8) ;
    BITMAPINFO bmpInfo = { 0 };
    bmpInfo.bmiHeader.biBitCount = uBitsPerPixel;
    bmpInfo.bmiHeader.biHeight = uHeight;
    bmpInfo.bmiHeader.biWidth = uWidth;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    if(bmpInfo.bmiHeader.biBitCount==32)  {
        bmpInfo.bmiHeader.biCompression=BI_RGB;
        //bmpInfo.bmiColors=NULL;
    }
        // Pointer to access the pixels of bitmap
    UINT * pPixels = 0;
    hBitmap = CreateDIBSection( hDC, (BITMAPINFO *)&
        bmpInfo, DIB_RGB_COLORS, (void **)&
        pPixels , NULL, 0);

    if ( !hBitmap )
        return hBitmap; // return if invalid bitmaps

    //SetBitmapBits( hBitmap, lBmpSize, pBits);
    // Directly Write
    memcpy(pPixels, pBits, lBmpSize );
    LPBITMAPINFOHEADER lpbi;                                          //Line 229
    lpbi = (LPBITMAPINFOHEADER)hBitmap;                               //Line 230
    return hBitmap;
}

HBITMAP ColorChange2Dlg::DIBToDDB( HANDLE hDIB, CDC& dc ) 
{ 
    LPBITMAPINFOHEADER lpbi; 
    HBITMAP hbm; 
    CPalette pal; 
    CPalette* pOldPal; 
    //CClientDC dc(NULL); 
    if (hDIB == NULL) 
        return NULL; 
    lpbi = (LPBITMAPINFOHEADER)hDIB;                                           //Line 243
    int nColors = lpbi->biClrUsed ? lpbi->biClrUsed : 1 << lpbi->biBitCount;   //Line 244


    BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ; 
    LPVOID lpDIBBits; 
    if( bmInfo.bmiHeader.biBitCount > 8 ) 
        lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors + 
        bmInfo.bmiHeader.biClrUsed) + 
        ((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0)); 
    else 
        lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors); 
    // Create and select a logical palette if needed 
    if( nColors <= 256 && dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE) 
    { 
        UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors); 
        LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; 
        pLP->palVersion = 0x300; 
        pLP->palNumEntries = nColors; 
        for( int i=0; i < nColors; i++) 
        { 
            pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed; 
            pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen; 
            pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue; 
            pLP->palPalEntry[i].peFlags = 0; 
        } 
        pal.CreatePalette( pLP ); 
        delete[] pLP; 
        // Select and realize the palette 
        pOldPal = dc.SelectPalette( &pal, FALSE ); 
        dc.RealizePalette(); 
    } 
    hbm = CreateDIBitmap(dc.GetSafeHdc(), // handle to device context 
        (LPBITMAPINFOHEADER)lpbi, // pointer to bitmap info header 
        (LONG)CBM_INIT, // initialization flag 
        lpDIBBits, // pointer to initialization data 
        (LPBITMAPINFO)lpbi, // pointer to bitmap info 
        DIB_RGB_COLORS ); // color-data usage 
    if (pal.GetSafeHandle()) 
        dc.SelectPalette(pOldPal,FALSE); 
    return hbm; 
} 

void ColorChange2Dlg::OnBnClickedButton1()
{
    // TODO: Add your control notification handler code here
    CClientDC dc(this);
    COLORREF *pix = (COLORREF *)malloc(255*255*sizeof(COLORREF));
    //int x = 1;
    if(pix!=NULL){
        for(int i=0;i<255;i++)
        {
            for(int j=0;j<255;j++)
            {
                pix[i*255+j] = RGB(i,j,0);
            }
        }
    }
    CDC tempDC;
    tempDC.CreateCompatibleDC(&dc);
    HBITMAP dib = CreateBitmapFromPixels(tempDC.m_hDC,255,255,8*sizeof(COLORREF),(BYTE*)pix);
    HBITMAP finalMap = DIBToDDB(dib,tempDC);
    HBITMAP oldMap = (HBITMAP)tempDC.SelectObject(finalMap);
    dc.BitBlt(201,50,255,255,&tempDC,0,0,SRCCOPY);
    tempDC.SelectObject(oldMap);
    tempDC.DeleteDC();
}

1 个答案:

答案 0 :(得分:1)

要编写兼容代码,最好不要直接访问位。您可以使用渐变函数和GDI或GDI +绘制函数来执行您想要的任何操作。

您想到的代码pix[i*255+j] = RGB(i,j,0);是32位图像。每个像素指向一种颜色。它不是调色板图像,其中每个像素指向颜色表中的条目。

如果显示为32位(大多数现代计算机都是,但请检查以确保),您可以使用以下代码执行此操作

CBitmap m_bitmap;
void CMyWnd::make_bitmap()
{
    if (m_bitmap.GetSafeHandle()) return;
    int w = 255; 
    int h = 255;
    int *pix = new int[w*h];
    for (int i = 0; i < w; i++) 
        for (int j = 0; j < h; j++)
            pix[i + j*w] = RGB(i, j, 0);
    m_bitmap.CreateBitmap(w, h, 1, 32, pix);
    delete[]pix;
}

绘制位图:

void CMyWnd::paint_bitmap(CDC &dc)
{
    if (!m_bitmap.GetSafeHandle()) return;
    CDC memdc;
    memdc.CreateCompatibleDC(&dc);
    HBITMAP oldbitmap = (HBITMAP)memdc.SelectObject(m_bitmap);

    BITMAP bm;
    m_bitmap.GetBitmap(&bm);

    dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memdc, 0, 0, SRCCOPY);
    memdc.SelectObject(oldbitmap);
}

void CMyWnd::OnPaint()
{
    __super::OnPaint();
    CClientDC dc(this);
    paint_bitmap(dc);
}

<小时/> 编辑:由于历史原因,RGB值向后保存为BGR。请改用此功能:

void CMyWnd::make_bitmap()
{
    if (m_bitmap.GetSafeHandle()) return;

    int w = 256;
    int h = 256;
    BYTE *pix = new BYTE[4*w*h];

    for (int i = 0; i < w; i++)
    {
        for (int j = 0; j < h; j++)
        {
            int p = (i + j*w) * 4;
            pix[p + 0] = 0;//blue
            pix[p + 1] = i;//green
            pix[p + 2] = j;//red
            pix[p + 3] = 0;//not used in GDI functions
        }
    }

    m_bitmap.CreateBitmap(w, h, 1, 32, pix);

    delete[]pix;
}