所以我遇到一个问题,即确定在尝试读取任何24bpp位图图像并在同一文件夹中重新创建它时出现了什么问题。它适用于一个图像,但不是我用它测试过的另外两个图像。从位图读取时,我使用标题本身中的信息。可以说我有三个问题。 1)我是否正确地从位图中读取? 2)我是否正确计算/使用/写入填充? 3)我输出正确吗? 第三个是与此图像及其输出确认否。
另外,为图像分配2d数组的原因是我可以尝试将位图旋转90度。
不幸的是我无法发布图片,拍摄的图片来自这里,rgb_24bpp.bmp http://pyglet.googlecode.com/svn/trunk/tests/image/
以下是用于从图像中读取和计算填充的代码。
ifstream myBitmap("rgb_24bpp.bmp", ios::binary | ios::beg);
// Get the total file size in bytes, testing file access
begin = myBitmap.tellg();
myBitmap.seekg(0, ios::end);
end = myBitmap.tellg();
// Actually reading image file
myBitmap.seekg( 0, ios::beg);
myBitmap.read((char*)FileHeader, sizeof(BITMAPFILEHEADER));
myBitmap.read((char*)InfoHeader, sizeof(BITMAPINFOHEADER));
test = myBitmap.tellg();
RGBQUAD ** Image = new RGBQUAD*[InfoHeader->biWidth];
for (int i = 0; i < InfoHeader->biWidth; ++i) {
Image[i] = new RGBQUAD[InfoHeader->biHeight];
}
int pitch = InfoHeader->biWidth * 3;
if (pitch % 4 != 0)
{
pitch += 4 - (pitch % 4);
}
int padding = pitch - (InfoHeader->biWidth * 3);
cout << "padding: " << padding << endl;
myBitmap.seekg(FileHeader->bfOffBits, ios::beg);
for (int i = InfoHeader->biHeight; i > 0; --i) {
for (int j = 0; j < InfoHeader->biWidth; ++j) {
myBitmap.read((char*)&Image[j][i], sizeof(RGBQUAD));
}
if (padding != 0) myBitmap.read(PadBuffer, padding);
}
myBitmap.close();
开始/结束/测试是所有streampos并打印在控制台上进行调试。 这是用于输出/重新创建图像的代码。
ofstream BitmapOut("Output.bmp");
BitmapOut.write((char*)FileHeader, sizeof(BITMAPFILEHEADER));
BitmapOut.write((char*)InfoHeader, sizeof(BITMAPINFOHEADER));
for (int i = InfoHeader->biHeight; i > 0; --i) {
for (int j = 0; j < InfoHeader->biWidth; ++j) {
BitmapOut.write((char*)&Image[j][i], sizeof(RGBQUAD));
}
if (padding != 0) BitmapOut.write("\0\0\0\0\0\0\0", padding);
}
BitmapOut.close();
我已经确认两个标题确实是正确的,并且可以在3个不同的测试中正确地从它们中提取数据。 利用这个人代码(对不起,这个项目只是非商业和自学)。 reading a .bmp file in c++
除了在RGBQUAD中注释掉保留并改为有效地构成RGBTRI之外。
答案 0 :(得分:0)
你可以这样做..而且,如果你不想制作一个临时数组来复制像素,你可以轻松地阅读,搜索,阅读,寻找等等。或者你可以只读全部一旦。有很多方法可以读取位图并且效率低/效率低。这取决于你想要的方式。另一种有效的方法是保存BitmapInfoHeader和BitmapFileHeader。然后,当您决定将位图写入磁盘时,只需先写入标题,然后再写入像素。更快更容易..我在这个例子中没有这样做。我会把这个留给你弄清楚。
以下是我为回答您的问题而编写的示例代码。我更喜欢使用一维数组。
#include <fstream>
#include <cstring>
#include <windows.h>
typedef struct
{
unsigned int width, height;
unsigned char* pixels;
} Bitmap;
void InitBitmap(Bitmap* bmp)
{
if (bmp)
{
bmp->width = 0;
bmp->height = 0;
bmp->pixels = NULL;
}
}
void FreeBitmap(Bitmap* bmp)
{
if (bmp && bmp->pixels)
{
bmp->width = 0;
bmp->height = 0;
delete[] bmp->pixels;
bmp->pixels = NULL;
}
}
bool ReadBitmap(const char* FilePath, Bitmap* bmp)
{
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!bmp || !hFile.is_open())
return false;
BITMAPINFO Info;
BITMAPFILEHEADER Header;
memset(&Info, 0, sizeof(Info));
memset(&Header, 0, sizeof(Header));
hFile.read((char*)&Header, sizeof(Header));
hFile.read((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));
bmp->width = Info.bmiHeader.biWidth;
bmp->height = Info.bmiHeader.biHeight < 0 ? -Info.bmiHeader.biHeight : Info.bmiHeader.biHeight;
size_t size = Info.bmiHeader.biSizeImage;
bmp->pixels = new unsigned char[size];
hFile.seekg(Header.bfOffBits, std::ios::beg);
hFile.read((char*)bmp->pixels, size);
hFile.close();
return true;
}
bool WriteBitmap(const char* FilePath, Bitmap* bmp)
{
std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
if (!bmp || !hFile)
return false;
BITMAPINFO Info;
BITMAPFILEHEADER Header;
memset(&Info, 0, sizeof(Info));
memset(&Header, 0, sizeof(Header));
Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Info.bmiHeader.biWidth = bmp->width;
Info.bmiHeader.biHeight = bmp->height;
Info.bmiHeader.biPlanes = 1;
Info.bmiHeader.biBitCount = 24;
Info.bmiHeader.biCompression = BI_RGB;
Info.bmiHeader.biSizeImage = 0;
Header.bfType = 0x4D42;
Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
size_t size = (((24 * bmp->width + 31) & ~31) / 8) * bmp->height;
hFile.write((char*)&Header, sizeof(Header));
hFile.write((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));
hFile.write((char*)bmp->pixels, size);
hFile.close();
return true;
}
int main()
{
Bitmap bmp;
InitBitmap(&bmp);
ReadBitmap("C:/Users/Brandon/Desktop/foo.bmp", &bmp);
WriteBitmap("C:/Users/Brandon/Desktop/foo2.bmp", &bmp);
FreeBitmap(&bmp);
}