2011-02-14 18 views
8

Tengo una matriz de bytes (que leo a través de una secuencia directamente desde un archivo .bmp y luego la almacena como un BLOB en una base de datos) que quiero mostrar como iconos en una CImageList. Por lo tanto, quiero de alguna manera cargar mis datos en un HBITMAP o CBitmap. He hecho así hasta ahora, la lectura de un archivo:array [byte] a HBITMAP o CBitmap

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

Pero, obviamente, que sólo funciona para archivos, pero no para byte-arrays. ¿Cómo puedo obtener el mismo resultado, pero leyendo desde una matriz de bytes?

Editar: Nota que mi matriz no contiene sólo la información de color, sino más bien el archivo completo como está escrito en el disco, incluyendo todos los encabezados y meta-datos. Me parece que descartar toda esa información es una mala idea.

+0

relacionadas (sentido contrario) [? Gdiplus :: mapa de bits para el conjunto de bytes] (http://stackoverflow.com/questions/3340017/gdiplusbitmap-to -byte-array) – jrh

Respuesta

16

suponiendo que tiene la información cargada en una matriz de bytes llamado bytes ....

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); 

Es un poco desordenado y podría usar una dosis fuerte de la comprobación de errores, pero la idea básica es el sonido.

+0

¡Trabajó de la caja! ¡Gracias! ¿Podría preguntar qué tipo de comprobaciones de error sugeriría? –

+3

@kdansky Compruebe que bmi, bmih y los bits están todos dentro de la matriz de bytes. Verifique que GetDC tuvo éxito. Verifique que CreateDIBitmap haya tenido éxito. También podría considerar el intercambio de GetDC (NULL) con una llamada más apropiada para obtener un DC. GetDC (NULL) usa el DC de toda la pantalla para determinar una profundidad de color adecuada, que puede o no ser adecuada, depende de para qué planifica usar el hbitmap. – Jon

+0

Si pudiera votar esto más, lo haría. Me ahorró horas. – acraig5075

2

La siguiente muestra podría ayudarlo.

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); 
0

Algo como esto funcionó para mí:


    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); 

(Esto se configura específicamente para colores de 32 bits, pero puede especificar cualquier tipo).

+0

Creo que no tengo un identificador de ventana (práctico) en el punto de mi código donde quiero escribir esto. ¿Existe una solución alternativa para la parte de GetDC()? –

+0

@Kdansky: solo puede usar la pantalla DC devuelta por 'GetDC (NULL)'. – casablanca

+0

Si bien esto no falla ni hace otras cosas malvadas, solo da como resultado que todas mis imágenes estén vacías. ¿Estás seguro de que funciona cuando la matriz contiene el mapa de bits completo, incluidos todos los encabezados? Realmente estoy almacenando archivos en mi base de datos, con todos los metadatos que existen, no solo los colores de píxel. –

0

Ok, aquí hay un ejemplo completo: 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; 
}