从数字数组创建 8 位位图
Posted
技术标签:
【中文标题】从数字数组创建 8 位位图【英文标题】:Creating 8 bit bitmap from array of numbers 【发布时间】:2014-01-21 17:10:18 【问题描述】:这一直困扰着我一段时间,我想确保我对位图的理解是正确的,并获得一些帮助发现错误。基本上我要做的是保存一个 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 + 调色板的代码(应该是从黑色到白色的值??)
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;
所以回顾一下问题/问题:
-
白色变成石灰绿色。
HBITMAP 无法在图片框内显示,调用 setimage 后该框变为纯黑色(是的,它设置为 SS_BITMAP)
我相信我可能在创建位图时遗漏了一些信息,并且我认为我需要实现一个设备上下文,尽管我不确定。我可以在 Windows 中打开文件,但如果我尝试在线上传它,它不喜欢这种格式。
我不知道如何管理对象的内存,所以我遇到了泄漏,如何在应用程序关闭之前使用 DeleteObject 进行清理? (可能是对话框的析构函数?)泄漏是 262144 字节,大约是图像的大小。
感谢您阅读这篇愚蠢的长篇文章。
编辑 我设法解决了绿色问题(第 1 号),我不知道如何解决,我认为这与标题上的内存大小不正确有关。它仍然无法上传到互联网或在程序中显示,所以它一定有问题。
【问题讨论】:
看不到您释放此行分配的缓冲区的位置:BITMAPINFO* pbmi = (BITMAPINFO*)alloca....
。另外,你在哪里删除这个缓冲区:bmp_data = new BYTE [R*C];
它们用于 CreateDIBSection,如果我在返回之前删除它们,我会得到错误。我是否认为一旦 HBITMAP 对象被删除(在某个时候)它们都不再存在?我确实删除了bmfh
,因为它在写入文件后就不需要了,对吗?
【参考方案1】:
所以我发现我的代码存在导致其他应用程序/互联网出错的问题。
在其中我为图像的高度分配了一个负值以翻转数据,但这是一个完全不正确的解决方案。而是:
// 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 太麻烦了。我欢迎就这部分提出意见,但现在我的所有问题都已解决。
【讨论】:
以上是关于从数字数组创建 8 位位图的主要内容,如果未能解决你的问题,请参考以下文章