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

标签 c++ image bitmap gdi

当我像这样设置和创建 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);

我得到这样的输出图像: image1

但是当我将位计数从 24 更改为 8(这也允许 3 倍的图像大小,允许我从 733 宽度变为图像的自然宽度 2200)时,我得到了这样的图像(伴随着很多不稳定性) ):

image2

我的输出看起来像这样:

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

所以我的问题是:

  • 当我从 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;
        }
    }

最佳答案

您应该创建一个调色板。试试这个:

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

然后当您调用 CreateDIBitmap 时,它将变为:

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

另请注意,您还应该小心地增加 BITMAPFILEHEADER 中的偏移量,以便它表示在实际像素数据之前定义了颜色调色板(昨天我遇到了困难,因为这个,参见 Creating 8bpp bitmap with GDI and saving it as a file ):

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

对于您的同事写的那个函数:最好使用 Luminance将颜色转换为灰度等效值: enter image description here

希望这有帮助:)

关于c++ - 如何使 8 位位图在 C++ 中显示为单色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14876685/

相关文章:

image - 全屏缩放背景图像叠加

C++ "operator+="和 "operator++"优先级问题

c++ - 自定义排序算法c++

html - 如何在 img 上获取背景图像?

java - 如何将位图压缩为较小尺寸的图像(保持纵横比)

c++ - Windows 工具栏 - 控制按钮大小和填充

java - 从 byte[] 创建位图

c++ - 如何构建用于分发的 SDL C++ 程序?

c++/正在寻找有关目录和文件的文档(如 dirent.h)?

html - 如何去除图像下方的虚线?