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

时间:2019-05-21 06:26:07

标签: c++ image bitmap

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

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

2 个答案:

答案 0 :(得分:0)

使用以下结构: BITMAPINFOHEADER

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;

答案 1 :(得分:0)

我为您编写了该功能的一个版本。我测试了它,成功了。

函数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>>的typedef。
Color24是我创建的用于处理RGB颜色的结构。

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

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

希望它能对您有所帮助。