FjjF
FjjF

Reputation: 87

Colors are not being correctly displayed

Just to learn Windows API, I'm trying to use a cheap fingerprint device I bought. The library that came with it captures the fingerprint as an 8bit bitmap of 256x280 pixels and stores the raw pixels in a buffer.

I'm trying to copy this raw pixel stream into a Device Independent Bitmap (DIB) and then trying to use this DIB to draw onto a window.

I managed to display the image but the colors are all wrong. Heres the piece of code that handles the painting.

PAINTSTRUCT ps;
HDC hdc,memDC;

HBITMAP cp_bmp;

HBITMAP di_bmp;
BITMAPINFO di_bmp_info;
void *di_bmp_data;

int ptr;
int x,y;

int aux;

ZeroMemory(&di_bmp_info,sizeof(BITMAPINFO));
di_bmp_info.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
di_bmp_info.bmiHeader.biWidth=256;
di_bmp_info.bmiHeader.biHeight=280;
di_bmp_info.bmiHeader.biPlanes=1;
di_bmp_info.bmiHeader.biBitCount=8;
di_bmp_info.bmiHeader.biCompression=BI_RGB;

hdc=BeginPaint(hwnd,&ps);

// create the DIB
di_bmp=CreateDIBSection(hdc,&di_bmp_info,DIB_RGB_COLORS,&di_bmp_data,NULL,0);

// Copy the original bitstream onto the DIB
CopyMemory(di_bmp_data,fingerprint,256*280);

// create the mem dc
memDC=CreateCompatibleDC(hdc);

// create the DDB
cp_bmp=CreateCompatibleBitmap(hdc,256,280);
SelectObject(memDC,cp_bmp);

SetDIBits(memDC,cp_bmp,0,280,di_bmp_data,&di_bmp_info,DIB_RGB_COLORS);
BitBlt(hdc,10,10,256,280,memDC,0,0,SRCCOPY);
DeleteObject(cp_bmp);   
EndPaint(hwnd,&ps);

Curious fact is that when I change the di_bmp_info.bmiHeader.biBitCount to 32, the colors display perfectly but the image gets smaller in size and gets repeated around 5 or six times horizontally.

Im stuck!. Thanks in advance.

Upvotes: 0

Views: 262

Answers (1)

Jonathan Potter
Jonathan Potter

Reputation: 37132

In short, you have an indexed bitmap (each pixel is not an RGB value but instead an index into a defined palette of colors) and you haven't provided a palette for it to use.

BITMAPINFO is a variable sized structure - a BITMAPINFOHEADER, followed by at least one but potentially more RGBQUAD structures. For indexed bitmap depths (8 bpp and below), a palette needs to be provided following the BITMAPINFOHEADER in memory.

The number of palette entries required is determined by the biBitCount and biClrUsed fields. If biClrUsed is 0 the number of palette entries must be 1 << biBitCount, or 256 in the case of 8bpp. Setting biClrUsed to something other than 0 lets you provide fewer palette entries if the bitmap doesn't need them.

Because you haven't set biClrUsed a full 256 color palette is assumed to follow the BITMAPINFOHEADER in memory and essentially random memory is being used.

BITMAPINFO provides only a single RGBQUAD itself so you need to extend the structure to provide the rest, for example:

struct MyBitmapInfo
{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD palette[256];
};

Where you actually get the palette from is up to you, but you could e.g. use a grayscale palette like this:

struct MyBitmapInfo di_bmp_info;

ZeroMemory(&di_bmp_info,sizeof(struct MyBitmapInfo));
di_bmp_info.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
di_bmp_info.bmiHeader.biWidth=256;
di_bmp_info.bmiHeader.biHeight=280;
di_bmp_info.bmiHeader.biPlanes=1;
di_bmp_info.bmiHeader.biBitCount=8;
di_bmp_info.bmiHeader.biCompression=BI_RGB;

// initialise greyscale palette
for (int i = 0; i < 256; i++)
{
    di_bmp_info.palette[i].rgbRed =
    di_bmp_info.palette[i].rgbGreen =
    di_bmp_info.palette[i].rgnBlue = i;
}

Upvotes: 4

Related Questions