2016-06-27 24 views
0

ピクセル値の配列をハードコードし、このピクセル配列をDIBに変換し、このDIBをDDBに変換することによってビットマップを作成しようとしています。 CreateBitmapFromPixelsとDIBToDDBをインターネット上で変換する関数が2つ見つかりました。私の問題は、プログラムが244行でクラッシュするということです。私は243行目で、lpbiがhDIBから情報を取得していないことを発見しました。次に、229行目と230行目にコードを追加して、BITMAPINFO構造体を作成した関数で同じことを行うことが役立つかどうかを確認しました。それでも、HBITMAPから何も得られなかった。ポインタにハンドルをキャストするのに間違っているものがあるかどうか、それは何をするのか、そして問題を解決できるようにDIBへのハンドルからHBITMAPINFOHEADERを取得する他の方法があるのだろうかと思います。MFCキャストへのポインタとDIBからDDBへの変換

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(); 
} 
+0

'dc.GetDeviceCaps(RASTERCAPS)&RC_PALETTE'このコードは古いディスプレイドライバ用です。最新のコンピュータは32ビットカラーをサポートしています。 256色以下の画像は、ピクセル情報が 'BITMAPINFO :: bmpColors'に含まれています。 GDI関数はパレットがあるので、手動でパレット関数を呼び出す必要はありません。あなたは何をしようとしているのかをより詳細に説明する必要があります(全体的な目標?) –

+0

各ピクセルが一意の赤と緑の色を持つ255×255のピクセルビットマップを作成します。 (すべてのピクセルに0の青があります)私は、DDBの代わりにDIBを使用して個々のピクセルの色を設定する必要があると聞いています。だから私はウェブを検索し、これを思いついた。 – varimax

答えて

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; 
} 
+0

非常に興味深い。私はあなたのコードを試して、それは働いた。私はDelete [] pixの直後にOnPaintを呼び出さなければならなかった。 CMyWnd :: make_bitmap();でこのOnPaint関数はCMyWnd :: OnPaintと異なるのですか? – varimax

+0

'void OnPaint()'はMFCで 'ON_WM_PAINT'を扱うために予約されています。直接呼び出さないでください。 –

+0

okay how about invalidateRect – varimax

関連する問題