如何使8位位图在C++中显示为单色?

xcd*_*n05 3 c++ gdi image bitmap

当我设置并创建这样的24位位图时:

   //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);
Run Code Online (Sandbox Code Playgroud)

我得到这样的输出图像: 此搜索

但是当我将bitcount从24改为8(这也允许3x图像大小,允许我从733宽度到图像的自然宽度2200),我得到这样的图像(以及很多不稳定性):

图像2

我的输出如下:

    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);
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  • 当我从24切换到8时,为什么会发生这种情况?
  • 有没有一种简单的方法可以将图像输出为单色而不是彩色?

最后一件事:

很久以前,我的同事为了类似的问题写了这个函数,但他说我可以使用它.不幸的是,我无法让它工作:

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Lih*_*ihO 6

你应该创建一个颜色托盘.试试这个:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后当你打电话时CreateDIBitmap它会变成:

hbit = CreateDIBitmap(hdc, &bmi.bmiHeader, CBM_INIT, m_imageData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
Run Code Online (Sandbox Code Playgroud)

另请注意,您应该小心增加您的偏移量,BITMAPFILEHEADER以便它表示在实际像素数据之前定义了颜色托盘(昨天我因此而遇到困难,请参阅使用GDI创建8bpp位图并保存它作为文件):

bf->bfOffBits = 54 + sizeof(RGBQUAD)*256;
Run Code Online (Sandbox Code Playgroud)

对于你的同事写的那个功能:最好使用Luminance将颜色转换为灰度等价物: 在此输入图像描述

希望这可以帮助 :)