如何生成位图头数据,然后使用 C++ 写入文件

how to generate bitmap header data then write into a file using c++

本文关键字:C++ 文件 然后 位图 何生成 数据      更新时间:2023-10-16

我想创建一个没有任何库的位图文件头。 这是我的图像数据:

width = 3px;
height = 10px;
bits_per_pixle = 24;

如何为其标头生成54 bytes数据,然后写入文件?我对此有很多问题。我不知道如何以十六进制将数据写入文件。我不知道如何在 4 字节等中写入文件大小。谁能帮我?谢谢。

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main()
{
int w = 3;
int h = 10;
int bits_per_pixle = 24;
ofstream des("file.bmp", ios::binary);
return 0;
}

使用以下结构: 位图信息标头

typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG  biWidth;
LONG  biHeight;
WORD  biPlanes;
WORD  biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG  biXPelsPerMeter;
LONG  biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

我已经为您编写了一个函数版本。我测试了它,它工作成功。

该函数createRawBitmap24()创建不压缩的位图图像,每像素 24 位:

struct Color24
{
uint8_t red;
uint8_t green;
uint8_t blue;
};
typedef std::vector<std::vector<Color24>> Image24;
bool check(const Image24 & img)
{
// check the shape
bool valid(!img.empty());
if(valid)
{
size_t line_size(img[0].size());
for(size_t i = 1; valid && (i < img.size()); ++i)
{
if(img.at(i).size() != line_size)
valid = false;
}
}
else
valid = false;
return valid;
}
bool createRawBitmap24(const std::string & file_path, const Image24 & img)
{
bool success(false);
if(check(img))
{
// ----- create the image in bmp format -----
// find the padding size
uint8_t padding_size(0);
size_t n = img[0].size()*3;
while(((n+padding_size) % 4) != 0)
++padding_size;
// build the raw content
const uint32_t ris = static_cast<uint32_t>(img.size()*(img[0].size()*3 + padding_size)); // raw image size
uint8_t * raw_content = new uint8_t[ris];
size_t cursor(0);
for(int i = static_cast<int>(img.size()-1); i >= 0; --i) // read lines in reverse order
{
for(const Color24 & pixel : img.at(static_cast<size_t>(i)))
{
raw_content[cursor++] = pixel.blue;
raw_content[cursor++] = pixel.green;
raw_content[cursor++] = pixel.red;
}
for(size_t j = 0; j < padding_size; ++j)
{
raw_content[cursor++] = 0xFF;
}
}
// build the header
const uint32_t hs(54); // header size
const uint32_t fs = (hs + ris); // file size
const uint32_t width = static_cast<uint32_t>(img[0].size()); // image width (without padding)
const uint32_t height = static_cast<uint32_t>(img.size()); // image height (without padding)
const uint32_t reso(2835); // resolution, ~72 DPI
const uint8_t header[hs] = {
'B', 'M',
static_cast<uint8_t>(fs & 0xFF), static_cast<uint8_t>((fs >> 8) & 0xFF), static_cast<uint8_t>((fs >> 16) & 0xFF), static_cast<uint8_t>((fs >> 24) & 0xFF),
0, 0,
0, 0,
static_cast<uint8_t>(hs & 0xFF), static_cast<uint8_t>((hs >> 8) & 0xFF), static_cast<uint8_t>((hs >> 16) & 0xFF), static_cast<uint8_t>((hs >> 24) & 0xFF),
40, 0, 0, 0,
static_cast<uint8_t>(width & 0xFF), static_cast<uint8_t>((width >> 8) & 0xFF), static_cast<uint8_t>((width >> 16) & 0xFF), static_cast<uint8_t>((width >> 24) & 0xFF),
static_cast<uint8_t>(height & 0xFF), static_cast<uint8_t>((height >> 8) & 0xFF), static_cast<uint8_t>((height >> 16) & 0xFF), static_cast<uint8_t>((height >> 24) & 0xFF),
1, 0,
24, 0,
0, 0, 0, 0,
static_cast<uint8_t>(ris & 0xFF), static_cast<uint8_t>((ris >> 8) & 0xFF), static_cast<uint8_t>((ris >> 16) & 0xFF), static_cast<uint8_t>((ris >> 24) & 0xFF),
static_cast<uint8_t>(reso & 0xFF), static_cast<uint8_t>((reso >> 8) & 0xFF), static_cast<uint8_t>((reso >> 16) & 0xFF), static_cast<uint8_t>((reso >> 24) & 0xFF),
static_cast<uint8_t>(reso & 0xFF), static_cast<uint8_t>((reso >> 8) & 0xFF), static_cast<uint8_t>((reso >> 16) & 0xFF), static_cast<uint8_t>((reso >> 24) & 0xFF),
0, 0, 0, 0,
0, 0, 0, 0
};
// ----- Write the content in the file -----
std::ofstream out_s(file_path, std::ofstream::binary);
if(out_s)
{
for(size_t i = 0; i < hs; ++i)
out_s << header[i];
for(size_t i = 0; i < ris; ++i)
out_s << raw_content[i];
out_s.close();
success = true;
}
delete [] raw_content;
}
return success;
}

要使用它,您只需调用函数createRawBitmap24()并将文件路径和要创建的Image24作为参数。
如您所见,Image24std::vector<std::vector<Color24>>的类型定义 .
Color24是我创建的用于处理 RGB 颜色的结构。

我使用的类型(uint8_tuint16_tuint32_t,...)是为了使其更具可读性。当位图规范说标头字段需要 1、2 或 4 个字节时,我使用了相应的显式类型。但是,如果您的平台中未定义这些类型,则可以将它们替换为unsigned charunsigned shortunsigned int(只需与sizeof()检查大小是否与 1、2 和 4 相同)。但是如果你能包括cstdint,那应该没问题。

当然,您可以根据需要调整该功能。

我希望它能帮助你。