简体   繁体   English

错误的位图复制/输出

[英]Incorrect Bitmap Copy/Output

So I am having a problem figuring out exactly what is going wrong with trying to read any 24bpp bitmap image and re-create it in the same folder. 因此,在尝试读取任何24bpp位图图像并在同一文件夹中重新创建图像时,我很难确定到底出了什么问题。 It works with one image, but not two others that I have tested it with. 它只能处理一个图像,但不能用于测试它的其他两个图像。 When reading from the bitmap, I use the information found in the header itself. 从位图读取时,我使用标题本身中的信息。 It could be said I have three questions. 可以说我有三个问题。 1) Am I reading from bitmap correctly? 1)我可以从位图正确读取吗? 2) Am I calculating/using/writing the padding correctly? 2)我是否正确计算/使用/编写填充? 3) Am I outputting correctly?. 3)我输出正确吗? Third is confirmed no with this image and its output. 第三,此图像及其输出确认为否。

Also the reason for allocating an 2d array for the Images is so that I can latter try to rotate bitmaps by 90 degrees. 另外,为Images分配2d数组的原因是为了让我以后可以尝试将位图旋转90度。

Unfortunately I cannot post images, the image taken is from here, the rgb_24bpp.bmp http://pyglet.googlecode.com/svn/trunk/tests/image/ 不幸的是,我无法发布图像,所拍摄的图像是从此处rgb_24bpp.bmp http://pyglet.googlecode.com/svn/trunk/tests/image/

Here is the code used for reading from the image and to calculate the padding. 这是用于从图像读取并计算填充的代码。

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 are all of streampos and printed on console for debugging. 开始/结束/测试是所有流媒体,并打印在控制台上以进行调试。 And this is the code used to output/recreate the image. 这是用于输出/重新创建图像的代码。

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();

I have confirmed that both headers are indeed correct and can pull data from them properly in 3 different tests. 我已经确认两个标头确实正确,并且可以在3个不同的测试中正确地从它们中提取数据。 Utilizing this guys code (sorry, this project is non-commercial and self-study only). 使用此人的代码(对不起,该项目是非商业性的且仅用于自学)。 reading a .bmp file in c++ 在C ++中读取.bmp文件

With the exception of commenting out the reserved in the RGBQUAD and making effectively a RGBTRI instead. 除了注释掉RGBQUAD中的保留项并有效地制作RGBTRI之外。

You can do it like this.. Also, if you don't want to make a temporary array to copy the pixels, you can easily read, seek, read, seek, etc.. OR you can just read all at once. 您可以这样操作。此外,如果您不想创建一个临时数组来复制像素,则可以轻松读取,查找,读取,查找等。或者也可以一次读取所有内容。 There are so many ways to read a bitmap and be efficient/inefficient. 有很多方法可以读取位图并且有效/无效。 It's up to you how you want to do it. 您要如何决定。 Another efficient way to do it is to SAVE the BitmapInfoHeader and BitmapFileHeader. 另一种有效的方法是保存BitmapInfoHeader和BitmapFileHeader。 Then when you decide to write the bitmap to the disk, just write them headers first then the pixels. 然后,当您决定将位图写入磁盘时,只需先将它们写入标头,然后再写入像素。 WAY faster and easier.. I did NOT do that in this example. 更快,更简单..在此示例中,我没有这样做。 I'll leave that up to you to figure out. 我将由您自己决定。

Here is a sample code I wrote for answering your question. 这是我为回答您的问题而编写的示例代码。 I prefer to use 1-dimensional arrays. 我更喜欢使用一维数组。

#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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM