从数组中创建8位位图

时间:2014-01-21 17:10:19

标签: c++ bitmap mfc

这一直困扰着我一段时间,我想确保我对位图的理解是正确的,并找到一些帮助发现错误。基本上我要做的是保存一个8位位图文件,同时将它显示在MFC应用程序的图片框中。我想避免使用繁琐的方法来保存位图,然后重新加载它。

保存文件操作大部分都是成功的,但是我改变了我的代码,现在文件中曾经是白色的(在这个例子中它是一个黑白图像)通常是绿色但它会改变。我猜这是因为我的数据可能引用了颜色表中的信息,哪个值是白色的?

HBITMAP ReadWrite::SaveFile(LPCTSTR file, double* data) {

    BYTE* bmp = ConvertData(data);
    HANDLE hf;
    BITMAPINFO* pbmi = WriteHeader(file);

    BITMAPFILEHEADER* bmfh = (BITMAPFILEHEADER*)alloca(sizeof(BITMAPFILEHEADER));
    bmfh->bfType = 0x4d42; // 'BM'
    bmfh->bfReserved1 = 0;
    bmfh->bfReserved2 = 0;
    bmfh->bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbmi->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
    bmfh->bfSize = (DWORD)(bmfh->bfOffBits + pbmi->bmiHeader.biSizeImage);


    hf = CreateFile(file, GENERIC_READ | GENERIC_WRITE, (DWORD) 0,
        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL );

    if (hf == NULL) // error creating
    {
        CloseHandle (hf);
        return NULL;
    }

    // write header
    unsigned long bwritten;
    if (!WriteFile(hf, (LPCVOID)bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL))
    {
        CloseHandle (hf);
        return NULL;
    }

    // write infoheader
    if (!WriteFile(hf, (LPCVOID)pbmi, sizeof (BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD), &bwritten, NULL ))
    {   
        CloseHandle (hf);
        return NULL;
    }

    // write image data
    if (!WriteFile(hf, (LPCVOID)bmp_data, (int) pbmi->bmiHeader.biSizeImage, &bwritten, NULL ))
    {   
        CloseHandle (hf);
        return NULL;
    }

    // Close
    CloseHandle(hf);

    // Send back a file to display
    return CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, (void**)bmp_data, NULL, 0);
}

编写infoheader + palette的代码(应该是从黑到白的值?)

BITMAPINFO* ReadWrite::WriteHeader(LPCTSTR fn)
{
    int R = ReadWrite::getR();
    int C = ReadWrite::getC();

    BITMAPINFO* pbmi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
    pbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = R;
    pbmi->bmiHeader.biHeight = -C;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = 8;
    pbmi->bmiHeader.biCompression = BI_RGB;
    pbmi->bmiHeader.biSizeImage = (((R * pbmi->bmiHeader.biBitCount + 31) & ~31) >> 3) * C;
    pbmi->bmiHeader.biClrUsed = 256;
    pbmi->bmiHeader.biClrImportant = 0; 
    for(int i=0; i<256; i++)
    {
        pbmi->bmiColors[i].rgbRed = i;
        pbmi->bmiColors[i].rgbGreen = i;
        pbmi->bmiColors[i].rgbBlue = i;
        pbmi->bmiColors[i].rgbReserved = 0;
    }

    //return true;
    return pbmi;
}

最后将我的数字数组转换为unsigned char'Bytes':

BYTE* ReadWrite::ConvertData(double* data) {

    BYTE* bmp_data;
    int R = ReadWrite::getR();
    int C = ReadWrite::getC();
    bool binary = ReadWrite::getBinary();

    bmp_data = new BYTE [R*C];

    // convert the values to unsigned char (BYTE)
    for(int i=0; i<R*C; i++){
        if (data[i] == 1){
            data[i] = 255;
        }
        bmp_data[i] = (unsigned char)data[i];
    }

    delete [] data;

    return bmp_data;
}

回顾一下问题/问题:

  1. 白色是柠檬绿。
  2. HBITMAP无法在图片框内显示,在调用setimage后该框变为黑色(是的,它设置为SS_BITMAP)
  3. 我相信我可能会错过位图创建中的一些信息,我认为我需要实现一个设备上下文,尽管我不确定。我可以在Windows中打开文件但如果我尝试在线上传它就不喜欢这种格式。
  4. 我不知道如何管理对象的内存,所以我得到了泄漏,如何在应用程序关闭之前使用DeleteObject进行清理? (对话的析构函数可能?)漏洞是262144字节,大约是图像的大小。
  5. 感谢您阅读这篇愚蠢的长篇文章。

    编辑我设法修复了绿色问题(编号1),我不知道怎么回事,我认为这与标题上的内存大小不一致有关。它仍然无法上传到互联网或显示在程序中,因此它必定是错误的。

1 个答案:

答案 0 :(得分:0)

所以我发现我的代码存在导致其他应用程序/互联网出错的问题。

在其中我为图像的高度指定负值以翻转数据,但这是一个完全不正确的解决方案。代替:

// convert the integer values to unsigned char (BYTE) BACKWARDS
for(int i=0; i<R; i++){
    for(int j=0; j<C; j++){
        if (data[i*R + j] == 1 && binary){
            data[i*R + j] = 255;
        }
        bmp_data[(R-i)*C + (j-C)] = (unsigned char)data[i*C + j];
    }
}

这样做是将原始值复制到bmp_data中,向后移动。这可确保数据正确存储并在应用程序中打开。我目前对DIBSection和内存管理的解决方案是删除所有数据并从文件重新加载图像。通过HBITMAP太过分了。我欢迎那方面的意见,但现在我所有的问题都得到解决。