【发布时间】:2015-03-03 19:31:56
【问题描述】:
我正在尝试了解如何输入/输出/处理图像,并且从一个错误到另一个错误,我得到了以下信息:
位图输出:
void createBMPFile(PBYTE image, BITMAPINFOHEADER bmi)
{
//DWORD stride = (((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3;
//bmi.biSizeImage = bmi.biHeight * stride;
BITMAPFILEHEADER bmf;
memset(&bmf, 0, sizeof(bmf));
// Fill BitmapFileHeader
INT cbHeaderOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
DWORD dwTotalBytes = cbHeaderOffBits + bmi.biSizeImage; // File size
bmf.bfType = 0x4d42; // Signature = 'BM'
bmf.bfSize = dwTotalBytes; // Bytes in whole file.
bmf.bfReserved1 = 0;
bmf.bfReserved2 = 0;
bmf.bfOffBits = cbHeaderOffBits; // Offset to bits in file.
// Flip the biHeight member so that it denotes top-down bitmap
// bmi.biHeight *= -1;
DWORD dwWritten = 0;
HANDLE hFile = NULL;
WCHAR wFileName[MAX_PATH] = TEXT("output.bmp");
hFile = CreateFileW(wFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return;
// Dump headers first
if (!WriteFile(hFile, &bmf, sizeof(BITMAPFILEHEADER), &dwWritten, NULL))
return;
if (!WriteFile(hFile, &bmi, sizeof(BITMAPINFOHEADER), &dwWritten, NULL))
return;
VERBOSE(TEXT("createBMPFile24: imageSize=%d width=%d height=%d \nbitCount=%d image=0x%08x\n"),
bmi.biSizeImage, bmi.biWidth, bmi.biHeight, bmi.biBitCount, image);
// Dump the data now
if (!WriteFile(hFile, image, bmi.biSizeImage, &dwWritten, NULL))
return;
CloseHandle(hFile);
}
位图输入:
PBYTE inputBMP(LPCWSTR filename, BITMAPINFOHEADER *bmi)
{
BITMAPFILEHEADER bmf;
memset(&bmf, 0, sizeof(bmf));
DWORD bytesread = 0;
HANDLE file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (file == INVALID_HANDLE_VALUE)
{
ERR(TEXT("Error creating file\n"));
return NULL;
}
if (!ReadFile(file, &bmf, sizeof(BITMAPFILEHEADER), &bytesread, NULL))
{
CloseHandle(file);
return NULL;
}
if (!ReadFile(file, bmi, sizeof(BITMAPINFOHEADER), &bytesread, NULL))
{
CloseHandle(file);
return NULL;
}
LONG width = bmi->biWidth;
LONG height = abs(bmi->biHeight);
if (bmi->biCompression != BI_RGB)
{
CloseHandle(file);
return NULL;
}
if (bmi->biBitCount != 24)
{
CloseHandle(file);
return NULL;
}
unsigned long size = bmi->biSizeImage - bmf.bfOffBits;
PBYTE Buffer = new BYTE[size];
if (SetFilePointer(file, bmf.bfOffBits, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
}
if (!ReadFile(file, Buffer, size, &bytesread, NULL) || bytesread == 0)
{
delete[] Buffer;
CloseHandle(file);
return NULL;
}
CloseHandle(file);
return Buffer;
}
调用者 - 输入位图,显示其内容,将其发送回输出
int main()
{
BITMAPINFOHEADER bitmapInfoHeader;
memset(&bitmapInfoHeader, 0, sizeof(bitmapInfoHeader));
PBYTE pSrcBitmap = inputBMP(TEXT("input.bmp"), &bitmapInfoHeader);
if (!pSrcBitmap)
return 1;
createBMPFile(pSrcBitmap, bitmapInfoHeader);
unsigned int h = abs(bitmapInfoHeader.biHeight);
unsigned int w = bitmapInfoHeader.biWidth;
for (unsigned int y = 0; y < h; ++y)
{
for (unsigned int x = 0; x < w; ++x)
{
VERBOSE(TEXT("(%2d %2d %3d %3d %3d) "), x, y,
pSrcBitmap[3 * (x + y * w)],
pSrcBitmap[3 * (x + y * w) + 1],
pSrcBitmap[3 * (x + y * w) + 2]);
}
VERBOSE(TEXT("\n"));
}
delete[] pSrcBitmap;
pSrcBitmap = NULL;
return 0;
}
我得到了非常奇怪的信息。
为了便于查看,我使用 Paint 制作了一个小矩形(黑白,但图像类型为 24 bpp)。
输出似乎有颜色...
但这不是我最大的问题。显示屏显示不均匀的信息(参见 x=14,y=5 。
我的字节似乎发生了变化……我不明白为什么,或者如何能够在一行上看到整行。如果图像不是矩形而是其他形状,这会导致数据的奇怪包装(第 1 行的字节放在第 2 行,移动更多字节......)
我怀疑这与步幅有关...但我不明白如何,因为图像是 24bpp...
不过,我尝试将 1 添加到这个特定的 bmp(w=35,h=10)
unsigned int w = bitmapInfoHeader.biWidth + 1;
突然间我的像素列表看起来很好(没有移位或换行):
我不明白为什么...或如何对任何尺寸的图像进行校正。
我试过了
if (w != (w / 4) * 4) w = (w / 4) * 4 + 1;
没用。
我需要能够循环遍历图像数据,而不是将其移位....有人可以解释一下这种移位/换行/字节未对齐的逻辑以及如何修复它们吗?
【问题讨论】:
-
位图文件格式比大多数人想象的要复杂得多。在读取/写入位图文件时,我总是建议使用预构建的解决方案。 Windows Imaging Component 是一个可行的选择。