我正在努力了解如何输入/输出/处理图像,并且从错误到错误我得到了以下内容:
位图输出:
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行的第1行字节放置,移动更多字节......)
我怀疑它与步幅有关......但我不明白如何,因为图像是24bpp ......
仍然,我试图在这个特定的bmp(w = 35,h = 10)
上加1unsigned int w = bitmapInfoHeader.biWidth + 1;
突然我的像素列表似乎很好(没有移位或换行):
我不明白为什么......或者如何对任何尺寸的图像进行校正。
我试过
if (w != (w / 4) * 4) w = (w / 4) * 4 + 1;
没有工作。
我需要能够遍历图像数据,而不是将其移位....有人可以解释一下这个移位/换行/字节未对齐的逻辑以及我如何修复它们?
答案 0 :(得分:2)
位图扫描线用0,1,2或3个字节进行零填充,这样就可以了 scanlinesize%4 == 0
这是你(概念上)读取位图(未压缩,24位)
的方式// bmi is a BITMAPINFOHEADER
// bmf is a BITMAPFILEHEADER
// fp is a FILE*
int w = bmi.biWidth;
int h = bmi.biHeight;
int scanlinesize = w*3;
while( scanlinesize%4 ) ++scanlinesize;
for(int y=0;y<h;++y)
{
fseek( fp, bmf.bfOffBits + scanlinesize*y, SEEK_SET );
for(int x=0;x<w;++x)
{
unsigned char rgb[3];
fread( rgb, 1, 3, fp );
// put rgb in the output here
}
}