I have written a version of the function for you. I tested it, it works successfully.
The function createRawBitmap24() creates a bitmap image without compression with 24 bits per pixel:
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;
}
To use it, you just have to call the function createRawBitmap24() and give as arguments the file path and the Image24 to create.
As you can see, Image24 is a typedef of std::vector<std::vector<Color24>>.
Color24 is the structure I created to handle RGB colors.
The types I used (uint8_t, uint16_t, uint32_t, ...) are to make it more readable. When the bitmap specification said 1, 2 or 4 bytes are needed for a header field, I used the corresponding explicit type. But if these types are not defined in your platform, you can replace them by unsigned char, unsigned short and unsigned int (just check with sizeof() if the sizes are the same to 1, 2 and 4). But if you can include cstdint, it should be fine.
Of course, you can adapt the function for your needs.
I hope it will help you.