【问题标题】:Creating a bitmap from raw headers and image data从原始标题和图像数据创建位图
【发布时间】:2013-02-02 00:46:44
【问题描述】:

我对在 C++ 中处理位图数据非常陌生,但我遇到了一个问题。我正在尝试关注维基百科中的this 示例。这是我正在使用的代码:

#include <iostream>
#include <fstream>
#include <Windows.h>

using namespace std;

int main()
{

    //fileheader
    BITMAPFILEHEADER* bf = new BITMAPFILEHEADER;
    bf->bfType = 66;
    bf->bfSize = 70;
    bf->bfOffBits = 54;

    //infoheader
    BITMAPINFOHEADER* bi = new BITMAPINFOHEADER;
    bi->biSize = 40;
    bi->biWidth = 2;
    bi->biHeight = 2;
    bi->biPlanes = 1;
    bi->biBitCount = 24;
    bi->biCompression = 0;
    bi->biSizeImage = 16;
    bi->biXPelsPerMeter = 2835;
    bi->biYPelsPerMeter = 2835;
    bi->biClrUsed = 0;
    bi->biClrImportant = 0;

    //image data
    unsigned char* thedata = new unsigned char;
    thedata[0] = 0;
    thedata[1] = 0;
    thedata[2] = 255;

    thedata[3] = 255;
    thedata[4] = 255;
    thedata[5] = 255;

    thedata[6] = 0;
    thedata[7] = 0;

    thedata[8] = 255;
    thedata[9] = 0;
    thedata[10] = 0;

    thedata[11] = 0;
    thedata[12] = 255;
    thedata[13] = 0;

    thedata[14] = 0;
    thedata[15] = 0;

    //dc
    HDC dc = GetDC(NULL);

    //bitmap info
    BITMAPINFO* bmi = (BITMAPINFO*)bi;

    //handle to bitmap
    HBITMAP hbmp = CreateDIBitmap(dc, bi, CBM_INIT, thedata, bmi, DIB_RGB_COLORS);

    //output to bmp....?
    ofstream outFile;
    outFile.open("outtestbmp.bmp");
    outFile << hbmp;
    outFile.close();

}

过去几天我一直在谷歌上搜索,试图弄清楚如何完成这项工作,但我似乎仍然无法成功。

这符合没有错误,但最后的outtestbmp.bmp文件是无法打开的。我是否犯了任何巨大的错误(可能有几十个)阻止它工作? (我高度怀疑使用 ofstream 输出我的 bmp 数据是错误的)。

编辑:有人告诉我将 bftype 设置为 66 是错误的。正确的值是多少?

另外,我创建了一个输出应该是什么的 .bmp 文件。这是该 bmp 的十六进制数据:

42 4D 46 00 00 00 00 00 00 00 36 00 00 00 28 00 00 00 02 00 00 00 02 00 00 00 01 00 18        
00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF  
FF FF 00 00 FF 00 00 00 FF 00 00 00

这是我正在输出的 .bmp 的数据:

42 00 46 00 00 00 CD CD CD CD 36 00 00 00 28 00 00 00 02 00 00 00 02 00 00 00 01 00 18 
00 00 00 00 00 10 00 00 00 13 0B 00 00 13 0B 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 
FF FF 00 00 FF 00 00 00 FF 00 00 00

【问题讨论】:

  • 您是否尝试过调试输出,例如通过使用 hexeditor 将数据与已知良好的简单 bmp 文件进行比较?
  • 不,我没有!我现在会得到一个十六进制编辑器并检查它。
  • 至少做:unsigned char* thedata = new unsigned char[16];
  • 正确的值在要链接到的维基百科文章和我下面的答案中给出。
  • 您可能应该添加 bf->bfReserved1 = 0 和 bf->bfReserved2 = 0;当您在堆上创建一个新对象时,该内存地址中存储的任何先前值都将仍然存在(或多或少)。

标签: c++ bitmap


【解决方案1】:
bf->bfType == 66;

这在两个方面是错误的。首先它是错误的值(神奇的值是小端机器上的字节 'BM' 或 0x4d42),其次它不是一个赋值。

然后:

unsigned char* thedata = new unsigned char;

只分配1个字符?

还有这个:

outFile << hbmp;

不做你认为它做的事。你只是在写一个句柄。您不需要创建位图,只需写出您已初始化的数据结构(一旦您将它们正确设置)。

你为什么要更新所有东西?不需要动态分配这些东西(你也不会删除它)。

我通常会这样做(为简洁起见,删除了一些代码):

BITMAPFILEHEADER bf;
bf.bfType = 0x4d42;
bf.bfSize = 70;
bf.bfOffBits = 54;

//infoheader
BITMAPINFOHEADER bi;
bi.biSize = 40;
bi.biWidth = 2;
etc...

//image data
unsigned char* thedata = new unsigned char[16]; // Should really calculate this properly
thedata[0] = 0;
....

//output to bmp....?
ofstream outFile;
outFile.open("outtestbmp.bmp");
outFile.write((char *)&bf,sizeof(bf));
outFile.write((char *)&bi,sizeof(bi));
outFile.write((char *)thedata, 16);
outFile.close();

【讨论】:

  • 对,我已经修复了,哈哈,我的错我忘记了当我复制我的代码时它还在。此外,如果我不添加新的 unsigned char,则会出现编译错误,因为指针未初始化。
【解决方案2】:

首先,您没有为所有像素分配足够的内存,它应该类似于

unsigned char* thedata = new unsigned char[numPixels * bytesPerPixel];

在您的情况下,2 by 2 图片和24 bpp(每像素位数),您应该分配 12 个字节。

每个像素将对应其redgreenblue 通道的一行中的三个字节。

注意:我从未使用过 Window 的位图创建过程,但我使用过许多库来处理图像,包括 FreeImageSDLGD

【讨论】:

  • 其实在这种情况下你应该分配16个字节。每行的宽度必须四舍五入到4字节的倍数;由于自然行大小是 2 个像素,每个像素 3 个字节,因此结果是 6 个字节,必须四舍五入为 8。2 行 8 个字节为 16 个字节。
【解决方案3】:

HBITMAP 是位图句柄,而不是实际位图。真正的位图存储在内核内存中。如果您只是将位图写入文件,则无需调用 GDI。即使它是一个实际的位图 cout 也需要一个运算符重载才能将内存结构实际写入文件,因为它在内存中的存储方式与在磁盘上的存储方式不同。

您需要做的就是将 BITMAPFILEHEADER 写入文件,然后将 BITMAPINFOHEADER 写入文件,然后写入数据(如果我们说的是 RGB,则为非索引)。

这里是有关位图如何实际存储在磁盘上的更多信息。

Bitmap Storage (MSDN)

从文件中读取位图是一样的。

【讨论】:

  • 那么outFile &lt;&lt; bf &lt;&lt; bi &lt;&lt; thedata; ?
  • 是的,只是数据需要是一组 RGBQUAD 结构 (struct RGBQUAD { char Blue; char Green; char Red; char Reserved;})。请查看该链接,它确实有助于解释位图的实际存储方式。
【解决方案4】:

首先,您需要为像素分配足够的数据:

unsigned char* thedata = new unsigned char[2 * 2 * 3];

然后你需要使用write,并以binary打开文件。

代替:

outFile.open("outtestbmp.bmp");
outFile << hbmp;

类似:

outFile.open("outtestbmp.bmp", ios::binary||ios::out);

outfile.write(reinterpret_cast<char *>(bf), sizeof(BITMAPFILEHEADER));
outfile.write(reinterpret_cast<char *>(bi), sizeof(BITMAPINFOHEADER));
outfile.write(reinterpret_cast<char *>(thedata), 2 * 2 * 3); 

outfile.close();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    相关资源
    最近更新 更多