3

When I set up and create a 24-bit bitmap like this:

   //fileheader
    BITMAPFILEHEADER* bf = new BITMAPFILEHEADER;
    bf->bfType = 0x4d42;
    bf->bfSize = 6054400 + 54;
    bf->bfOffBits = 54;

    //infoheader
    BITMAPINFOHEADER* bi = new BITMAPINFOHEADER;
    bi->biSize = 40;
    bi->biWidth = 2752;
    bi->biHeight = -733;
    bi->biPlanes = 1;
    bi->biBitCount = 24;
    bi->biCompression = 0;
    //bi->biSizeImage = 6054400;
    bi->biXPelsPerMeter = 2835;
    bi->biYPelsPerMeter = 2835;
    bi->biClrUsed = 0;
    bi->biClrImportant = 0;

    pFrame->GetImage(m_imageData);

    //
    //create bitmap...
    //(hbit is a global variable)

    BITMAPINFO* bmi;
    bmi = (BITMAPINFO*)bi; 
    HDC hdc = ::GetDC(NULL);

    hbit = CreateDIBitmap(hdc, bi, CBM_INIT, m_imageData, bmi, DIB_RGB_COLORS);

I get an output image like this: image1

But when I change bitcount from 24 to 8 (which also allows for 3x image size, allowing me to go from 733 width to the image's natural width of 2200), I get an image like this (along with a lot of instability):

image2

My output looks like this:

    BITMAP* bi = new BITMAP;
    CBitmap bmp;
    bmp.Attach(hbit);
    CClientDC dc(pWnd);
    CDC bmDC;
    bmDC.CreateCompatibleDC(&dc);
    CBitmap *pOldbmp = bmDC.SelectObject(&bmp);
    bmp.GetBitmap(bi);
    dc.BitBlt(384,26,bi->bmWidth/3,bi->bmHeight,&bmDC,0,0,SRCCOPY);
    //note: if bitcount is 8, height and width need to be /3, 
          //if 24, only width gets /3 
    bmDC.SelectObject(pOldbmp);

    //explicitly delete everything just to be safe
    delete bi;
    DeleteObject(bmp);
    DeleteObject(dc);
    DeleteObject(pOldbmp);
    DeleteObject(bmDC);

So my questions are:

  • Why is this happening when I switch from 24 to 8?
  • Is there an easy way to output the image as monochrome rather than color?

One last thing:

My coworker wrote this function a long time ago for a similar issue, but he said I may be able to use it. I can't get it to work, unfortunately:

void CopyMono8ToBgrx(byte* pDestBlue, byte* pDestGreen, byte *pDestRed, byte* pDestAlpha)
    {
        byte*               pSrc;
        byte*               pSrcEnd;

        pSrc = ( byte* ) m_imageData;
        pSrcEnd = pSrc + ( 2752*2200 );

        while ( pSrc < pSrcEnd )
        {
            byte data = *pSrc;

            *pDestBlue  = data;
            *pDestGreen = data;
            *pDestRed   = data;
            *pDestAlpha = 255;  // alpha is always 255 (fully opaque)

            pSrc++;
            pDestBlue   += 4;
            pDestGreen  += 4;
            pDestRed    += 4;
            pDestAlpha  += 4;
        }
    }
4

2 回答 2

6

You should create a color pallete. Try this:

struct BITMAPINFO256 {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[256];
} bmi;
memset(&bmi, 0, sizeof(BITMAPINFO256));
bmi.bmiHeader.biSize = 40;
bmi.bmiHeader.biWidth = 2752;
bmi.bmiHeader.biHeight = -733;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 8;
bmi.bmiHeader.biCompression = 0;
bmi.bmiHeader.biXPelsPerMeter = 2835;
bmi.bmiHeader.biYPelsPerMeter = 2835;
bmi.bmiHeader.biClrUsed = 256;
bmi.bmiHeader.biClrImportant = 0;
for (unsigned int i = 0; i < 256; i++) {
    bmi.bmiColors[i].rgbRed   = i;
    bmi.bmiColors[i].rgbGreen = i;
    bmi.bmiColors[i].rgbBlue  = i;
}

And then when you call CreateDIBitmap it will become:

hbit = CreateDIBitmap(hdc, &bmi.bmiHeader, CBM_INIT, m_imageData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);

Also note that you should be careful to also increase the offset in your BITMAPFILEHEADER so that it it expresses that there is color pallete defined before the actual pixels data (yesterday I was having hard time because of this, see Creating 8bpp bitmap with GDI and saving it as a file):

bf->bfOffBits = 54 + sizeof(RGBQUAD)*256;

And to that function that your coworker wrote: It's better to use Luminance to convert colors to gray-scale equivalents: enter image description here

Hope this helps :)

于 2013-02-14T15:01:40.640 回答
2

8 bit per pixel images are assuming a color palette following BITMAPINFOHEADER structure (see BITMAPINFO::bmiColors). If you make the palette to be 256 gray shades, the image is going to me 8 bpp grayscale. Now it's color with random colors on it.

The function CopyMono8ToBgrx you quoted creates full color bitmap, with gray individual pixels (R=G=B).

于 2013-02-14T14:24:39.587 回答