从原始标题和图像数据创建位图
Creating a bitmap from raw headers and image data
我对C++操作位图数据非常陌生,我有一个问题。 我正在尝试遵循维基百科中的这个例子。 这是我正在使用的代码:
#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
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* thedata = new unsigned char[numPixels * bytesPerPixel];
在您的情况下,使用2
图片和24 bpp
(每像素位数)2
,您应该分配 12 个字节。
每个像素将对应于其red
、green
和blue
通道的连续三个字节。
注意:我从未使用过 Window 的位图创建过程,但我使用了许多库来处理图像,包括 FreeImage
、SDL
和 GD
HBITMAP 是位图的句柄,而不是实际的位图。实际位图存储在内核内存中。如果只是将位图写入文件,则无需对 GDI 进行任何调用。即使它是一个实际的位图cout也需要一个运算符重载才能实际将内存结构写入文件,因为它存储在内存中与在磁盘上不同。
您需要做的就是将 BITMAPFILEHEADER 写入文件,然后将 BITMAPINFOHEADER 写入文件,然后写入数据(如果我们谈论的是 RGB,则未索引)。
下面是有关如何在磁盘上实际存储位图的详细信息。
位图存储 (MSDN)
从文件中读取位图是一样的。
首先,您需要为像素分配足够的数据:
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();
- 从 bmp 文件数据创建 MFC CBitmap
- 如何在 QML 中使用从 c++ 公开的序列数据创建图表
- c++用输入数据创建数组
- 使用 2D 数据创建 3D 直方图(OpenCV?
- 如何使C++代码更快:使用 CFile 从相机数据创建.csv文件
- 使用 C++ 从 16 位数据创建灰度图像
- 如何根据过滤的数据创建笛卡尔产品范围
- C 双重调度,出厂模式或一种从接收到的序列数据创建派生对象的方法
- 为 ppm/pgm 图像数据创建存储
- 如何从二进制数据创建 QIcon
- 基于输入数据创建 STL 向量 - 标量或复杂类型
- DirectX11如何从未签名的char*数据创建Texture2D
- 使用相机的初始数据创建d3d11Texture2D
- OpenCV C++:从存储在 int 向量的索引中为垫子类型数据创建列范围
- 如何使用矢量中的数据创建矢量
- 从单独文件(C++)中的用户输入数据创建矢量
- 为二进制数据创建字符串缓冲区的最佳方法
- 使用Media Foundation从原始数据创建AAC文件
- 在Visual Studio 2013中使用c++中的对象字段数据创建图表
- 如何从变量数据创建std::initializer_list