2013-04-10 3 views
8

J'ai un tableau de pixels que j'ai besoin de convertir en HBITMAP pour l'afficher dans une fenêtre. J'ai essayé d'utiliser CreateDIBitmap() mais je n'ai pas les en-têtes BMP. J'ai essayé de les construire manuellement selon la documentation de MSDN mais cela n'a pas fonctionné.Comment convertir un tableau de pixels en HBITMAP

Voici comment mon code ressemble

HBITMAP hBitmap 
char pixels[160*120]; // White grayscale image of size 160x120 
memset(pixels,255,sizeof(pixels)); 

BITMAPINFOHEADER bmih; 
bmih.biSize  = sizeof(BITMAPINFOHEADER); 
bmih.biWidth = 160; 
bmih.biHeight = -120; 
bmih.biPlanes = 1; 
bmih.biBitCount = 8; 
bmih.biCompression = BI_RGB ; 
bmih.biSizeImage = 0; 
bmih.biXPelsPerMeter = 10; 
bmih.biYPelsPerMeter = 10; 
bmih.biClrUsed =0; 
bmih.biClrImportant =0; 

BITMAPINFO dbmi; 
dbmi.bmiHeader = bmih; 
dbmi.bmiColors->rgbBlue = 0; 
dbmi.bmiColors->rgbGreen = 0; 
dbmi.bmiColors->rgbRed = 0; 
dbmi.bmiColors->rgbReserved = 0; 
void* bits = (void*)&(pixels[0]); 
hBitmap = CreateDIBitmap(localDC, &bmih, CBM_INIT, qB.bmBits, &dbmi, DIB_RGB_COLORS); 

Maintenant, j'obtenir un hBitmap non NULL qui est bon, mais il montre toujours l'image noire comme si elle ne pointe pas vers la matrice de pixels. Je l'ai vérifié en utilisant le code

BITMAP qB; 
GetObject(reinterpret_cast<HGDIOBJ>(hBitmap),sizeof(BITMAP),reinterpret_cast<LPVOID>(&qB)); 

Et en effet qB.bmBits est NULL. Quel est le problème et comment le résoudre?

+0

Je ne pense pas que CreateDIBi tmap prend en charge les images en niveaux de gris. Vous pouvez créer une palette de 256 nuances de gris ou vous pouvez convertir votre image en triplets RVB. – john

+0

OK, supposons que je le fasse: char pixels [160 * 120 * 3]; que j'ai l'image RVB. – DanielHsH

+0

J'ai défini bmih.biBitCount = 24; mais je ne fonctionne toujours pas – DanielHsH

Répondre

6

J'ai trouvé comment le faire. Nous devons utiliser CreateDIBSection() au lieu de CreateDIBitmap() Voici donc le code de travail

HBITMAP hBitmap = NULL; 
    unsigned char pixels[160*120*3]; 
    for (int i=0; i<160*120*3; i++){ 
     pixels[i] = (i%4==1)*255;  // An BGR (not RGB) 160x120 image. 
    } 
BITMAPINFOHEADER bmih; 
bmih.biSize  = sizeof(BITMAPINFOHEADER); 
bmih.biWidth = 160; 
bmih.biHeight = -120; 
bmih.biPlanes = 1; 
bmih.biBitCount = 24; 
bmih.biCompression = BI_RGB ; 
bmih.biSizeImage = 0; 
bmih.biXPelsPerMeter = 10; 
bmih.biYPelsPerMeter = 10; 
bmih.biClrUsed =0; 
bmih.biClrImportant =0; 

BITMAPINFO dbmi; 
ZeroMemory(&dbmi, sizeof(dbmi)); 
dbmi.bmiHeader = bmih; 
dbmi.bmiColors->rgbBlue = 0; 
dbmi.bmiColors->rgbGreen = 0; 
dbmi.bmiColors->rgbRed = 0; 
dbmi.bmiColors->rgbReserved = 0; 
void* bits = (void*)&(pixels[0]); 

// Create DIB 
hBitmap = CreateDIBSection(localDC, &dbmi, DIB_RGB_COLORS, &bits, NULL, 0); 
if (hBitmap == NULL) { 
    ::MessageBox(NULL, __T("Could not load the desired image image"), __T("Error"), MB_OK); 
    return; 
} 
// copy pixels into DIB. 
memcpy(bits,pixels,sizeof(pixels)); 

Pour les images en niveaux de gris, copier les pixels à DIB dans une boucle au lieu de avec memcpy()

#define INTENSITY unsigned char 

INTENSITY* dest = (INTENSITY*)bits; 
const INTENSITY* src = .. Put your char array of pixels; 
for (int j=0; j<imageWidth; j++){ 
    for (int i=0; i<imageHeight; i++, src++){ 
     *dest++ = *src; 
     *dest++ = *src; 
     *dest++ = *src; 
    } 
    // Padd the line to round WORD. 
    if (imageWidth%2) 
     *dest++ = 0; 
} 
+0

Note: Vous devrez peut-être tamponner la largeur au multiple de 4 octets (entier 32bits) au lieu de 16bits WORD comme je l'ai fait dans l'exemple. – DanielHsH

+2

Je ne pense pas 'void * bits = (void *) & (pixels [0]);' a un sens ici. Devrait juste le faire: 'void * bits = NULL;'. –

3

Votre post était très utile (la réponse) mais cela n'a pas fonctionné pour moi, voici le code avec de petites corrections:

// creating input 

    unsigned char pixels[160*120*3]; 
    for (int i=0; i<160*120*3; i++){ 
     pixels[i] = (i%4==1)*255;  // An BGR (not RGB) 160x120 image. 

    // at this point we have some input 

    BITMAPINFOHEADER bmih; 
    bmih.biSize  = sizeof(BITMAPINFOHEADER); 
    bmih.biWidth = 160; 
    bmih.biHeight = -120; 
    bmih.biPlanes = 1; 
    bmih.biBitCount = 24; 
    bmih.biCompression = BI_RGB ; 
    bmih.biSizeImage = 0; 
    bmih.biXPelsPerMeter = 10; 
    bmih.biYPelsPerMeter = 10; 
    bmih.biClrUsed =0; 
    bmih.biClrImportant =0; 

    BITMAPINFO dbmi; 
    ZeroMemory(&dbmi, sizeof(dbmi)); 
    dbmi.bmiHeader = bmih; 
    dbmi.bmiColors->rgbBlue = 0; 
    dbmi.bmiColors->rgbGreen = 0; 
    dbmi.bmiColors->rgbRed = 0; 
    dbmi.bmiColors->rgbReserved = 0; 

    HDC hdc = ::GetDC(NULL); 

    HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS); 
    if (hbmp == NULL) { 
     ::MessageBox(NULL, L"Could not load the desired image image", L"Error", MB_OK); 
     return; 
    } 

    ::ReleaseDC(NULL, hdc); 

    // a little test if everything is OK 
    OpenClipboard(NULL); 
    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP, hbmp); 
    CloseClipboard(); 

    // cleanup 
    DeleteObject(hbmp); 
Questions connexes