【问题标题】:array[byte] to HBITMAP or CBitmaparray[byte] 到 HBITMAP 或 CBitmap
【发布时间】:2011-06-26 23:35:50
【问题描述】:

我有一个字节数组(我直接从 .bmp 读取流,然后将其作为 BLOB 存储在数据库中),我想在 CImageList 中显示为图标。因此,我想以某种方式将我的数据加载到 HBITMAP 或 CBitmap 中。到目前为止,我已经这样做了,从文件中读取:

hPic = (HBITMAP)LoadImage(NULL, strPath, IMAGE_BITMAP, dwWidth, dwHeight, LR_LOADFROMFILE | LR_VGACOLOR);
...
CBitmap bitmap;
bitmap.Attach(hPicRet);

但显然,这只适用于文件,但不适用于字节数组。如何获得相同的结果,但从字节数组中读取?

编辑: 请注意,我的数组不仅包含颜色信息,还包含写入磁盘上的完整文件,包括所有标题和元数据。在我看来,丢弃所有这些信息是个坏主意。

【问题讨论】:

标签: c++ mfc


【解决方案1】:

假设您已将信息加载到名为 bytes.... 的 BYTE 数组中。

BITMAPFILEHEADER* bmfh;
bmfh = (BITMAPFILEHEADER*)bytes;

BITMAPINFOHEADER* bmih;
bmih = (BITMAPINFOHEADER*)(bytes + sizeof(BITMAPFILEHEADER));
BITMAPINFO* bmi;
bmi = (BITMAPINFO*)bmih;

void* bits;
bits = (void*)(bytes + bmfh->bfOffBits);

HDC hdc = ::GetDC(NULL);

HBITMAP hbmp = CreateDIBitmap(hdc, bmih, CBM_INIT, bits, bmi, DIB_RGB_COLORS) ;

::ReleaseDC(NULL, hdc);

这有点乱,可以使用大量的错误检查,但基本的想法是合理的。

【讨论】:

  • 开箱即用!谢谢!请问您会建议什么样的错误检查?
  • @kdansky 验证 bmi、bmih 和 bits 是否都在字节数组中。验证 GetDC 是否成功。验证 CreateDIBitmap 是否成功。您还可以考虑使用更合适的调用交换 GetDC(NULL) 来获取 DC。 GetDC(NULL) 使用整个屏幕的 DC 来计算合适的颜色深度,这可能合适也可能不合适 - 这取决于您计划使用 hbitmap 的目的。
【解决方案2】:

以下示例可以帮助您。

BITMAPINFO bmInfo;
BITMAPINFOHEADER &bmInfohdr = (BITMAPINFOHEADER)bmInfo.bmiHeader;

bmInfohdr.biSize = 40 + 255; //I think it's not of use
bmInfohdr.biWidth = x;
bmInfohdr.biHeight = y;
bmInfohdr.biPlanes=1;
bmInfohdr.biBitCount=8;
bmInfohdr.biCompression=0;
bmInfohdr.biSizeImage=0;
bmInfohdr.biXPelsPerMeter = 0;
bmInfohdr.biYPelsPerMeter = 0;
bmInfohdr.biClrUsed = 0;
bmInfohdr.biClrImportant = 0;

           // should I allocate memory further than the 
           // bmColors[1]?? anyway the compiler gives an
           // error for type mismatch!
//bmInfo.bmiColors = (RGBQUAD *) 
                  malloc(sizeof(RGBQUAD) * 256);

// here I define the 256 graylevel palette
for (int i=0; i<256; i++)
{
   bmInfo.bmiColors[i].rgbRed = i;
   bmInfo.bmiColors[i].rgbGreen = i;
   bmInfo.bmiColors[i].rgbBlue = i;
}


BYTE *matrix;
matrix = (BYTE*)malloc(size*sizeof(BYTE));
// here I put the BYTE values of the pixels

CDC *pdcDest = this->GetDC();

HBITMAP hBmp = CreateDIBitmap( pdcDest->m_hDC,
                &bmInfohdr,
                CBM_INIT,
                matrix,    
                &bmInfo,
                DIB_RGB_COLORS);
m_bmpBitmap.Attach( hBmp );

【讨论】:

    【解决方案3】:

    这样的事情对我有用:

    
       int bitmap[WX*WY];  // truecolor bitmap data
       BITMAPINFO bm = { sizeof(BITMAPINFOHEADER), WX, WY, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
       HBITMAP bmp = CreateDIBSection( GetDC(win), &bm, DIB_RGB_COLORS, (void**)&bitmap, 0,0 );
    

    (这是专门为 32 位颜色配置的,但您可以指定任何种类)。

    【讨论】:

    • 我相信在我的代码中我想写这个的地方没有(实用的)窗口句柄。 GetDC() 部分是否有解决方法?
    • @Kdansky:你可以直接使用GetDC(NULL)返回的屏幕DC。
    • 虽然这不会崩溃或做其他坏事,但它只会导致我所有的图片都是空的。当数组包含完整的位图(包括所有标题)时,您确定它有效吗?我真的将文件存储在我的数据库中,其中包含所有元数据,而不仅仅是像素颜色。
    【解决方案4】:

    好的,这是一个完整的例子:http://nishi.dreamhosters.com/u/so_bmp_v0.zip

    #include <stdio.h>
    #include <windows.h>
    
    #pragma comment(lib,"gdi32.lib")
    #pragma comment(lib,"user32.lib")
    
    char buf[1<<22];
    
    int main( int argc, char **argv ) {
    
      FILE* f = fopen( "winnt.bmp", "rb" ); if( f==0 ) return 1;
      fread( buf, 1,sizeof(buf), f );
      fclose(f);
    
      BITMAPFILEHEADER& bfh = (BITMAPFILEHEADER&)buf[0];
      BITMAPINFO& bi = (BITMAPINFO&)buf[sizeof(BITMAPFILEHEADER)];
      BITMAPINFOHEADER& bih = bi.bmiHeader; 
      char* bitmap = &buf[bfh.bfOffBits];
    
      int WX=1024, WY=512; // window's width/height
      int SX=bih.biWidth, SY=bih.biHeight;
    
      HWND win = CreateWindow( "STATIC", "Bitmap test", 0x90C0, 0,0, WX,WY, 0,0, GetModuleHandle(0), 0 );
    
      MSG msg;
      PAINTSTRUCT ps;
      HDC DC = GetDC(win); // window's DC
      HBITMAP dib = CreateDIBitmap( DC, &bih, CBM_INIT, bitmap, &bi, DIB_RGB_COLORS );
      HDC dibDC = CreateCompatibleDC( DC ); SelectObject( dibDC, dib );
    
      ShowWindow( win, SW_SHOWNOACTIVATE );
      SetFocus( win );
    
      while( GetMessage(&msg,win,0,0) ) {
        int m = msg.message;
        if( m==WM_PAINT ) {
          DC = BeginPaint( win, &ps );
          StretchBlt( DC, 0,0,WX,WY, dibDC,0,0,SX,SY, SRCCOPY );
          EndPaint( win, &ps );
        } else if( (m==WM_KEYDOWN) || (m==WM_SYSKEYDOWN) ) {
          break; 
        } else {
          DispatchMessage(&msg);
        }
      }
    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 2019-04-04
      • 1970-01-01
      • 2014-07-21
      • 2016-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多