c++ - MFC 将 Handle 转换为指针并将 DIB 转换为 DDB

标签 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();
}

最佳答案

要编写兼容的代码,最好不要直接访问位。您可以使用渐变函数和 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;
}

关于c++ - MFC 将 Handle 转换为指针并将 DIB 转换为 DDB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38045466/

相关文章:

c++ - 两次连续的套接字读取,第二次读取不起作用

c++ - 如何从 QLineEdit 连接焦点事件?

c++ - 为什么 std::move 表现得像 std::copy?

c++ - _snprintf_s 调用 [applicaiton].exe 已触发断点

visual-c++ - MFC Cstring 类的拆分功能

支持 OpenGL 的 C++ GUI 工具包

c++ - 使用 Gmail 帐户通过 C++ 发送电子邮件

c++ - Visual C++ CRT调试

visual-c++ - 如何在vc++ mfc中使用非静态方法创建线程

c++ - 如何从UTF16编码的字符串中获取解码后的字符串