我对在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
答案 0 :(得分:3)
bf->bfType == 66;
这有两个错误。首先它是错误的值(神奇值是小端机器上的字节&#39; BM&#39;或0x4d42),其次它不是一个赋值。
然后:
unsigned char* thedata = new unsigned char;
仅分配 1 char?
而且:
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();
答案 1 :(得分:1)
首先,你没有为所有像素分配足够的内存,它应该是
的内容unsigned char* thedata = new unsigned char[numPixels * bytesPerPixel];
在您的情况下,使用2
按2
图片和24 bpp
(每像素位数),您应该分配12个字节。
每个像素将对应red
,green
和blue
频道的一行中的三个字节。
注意:我从未使用Window的位图创建过程,但我使用了许多库来处理图像,包括FreeImage
,SDL
和GD
答案 2 :(得分:1)
HBITMAP是位图的句柄而不是实际的位图。实际位图存储在内核内存中。如果只是将位图写入文件,则无需对GDI进行任何调用。即使它是一个实际的位图,cout也需要一个操作符重载来实际将内存结构写入文件,因为它不存储在内存中与磁盘上相同。
您需要做的就是将BITMAPFILEHEADER写入文件,然后将BITMAPINFOHEADER写入文件,然后写入数据(如果我们说的是RGB,非索引)。
以下是有关位图实际存储在磁盘上的更多信息。
从文件中读取位图是一样的。
答案 3 :(得分:0)
首先,您需要为像素分配足够的数据:
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();