【问题标题】:Incorrect Bitmap Copy/Output位图复制/输出不正确
【发布时间】:2014-07-23 21:09:19
【问题描述】:

所以我很难弄清楚尝试读取任何 24bpp 位图图像并在同一文件夹中重新创建它时到底出了什么问题。它适用于一张图片,但不适用于我测试过的另外两张图片。从位图读取时,我使用在标题本身中找到的信息。可以说我有三个问题。 1)我是否正确地从位图读取? 2)我是否正确计算/使用/编写填充? 3)我输出正确吗? 第三个是用这张图片及其输出确认否。

另外,为图像分配二维数组的原因是,我可以稍后尝试将位图旋转 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();

begin/end/test 都是 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。

【问题讨论】:

  • 是否有某些原因在堆上为每个像素单独分配空间?
  • 我这样做是为了更简单/更容易理解,在看这里stackoverflow.com/questions/936687/… 之后,我意识到这很繁重且效率低下,但它为我自己简化了二维数组的使用。
  • 我通过使用诸如 MS PAINT 之类的工具制作了一些测试文件来处理 BMP 文件,并在每个角落创建具有单个不同颜色像素的纯白色或纯黑色文件。这使得使用调试器轻松执行代码并确保行对齐正确。在使用 BMP 时,行对齐是我大部分问题的根源。
  • 您的代码在哪个输入文件中运行良好?
  • 是的,您对padding 的计算看起来是正确的。您确定图像是 24 位而不是 32 位吗?

标签: c++ bitmap


【解决方案1】:

你可以这样做。另外,如果你不想制作一个临时数组来复制像素,你可以轻松地读取、查找、读取、查找等。或者你可以在一次。有很多方法可以读取位图并且高效/低效。这取决于你想怎么做。另一种有效的方法是保存 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 2023-04-02
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多