Home > Mobile >  bitmap artifacts when generated in c
bitmap artifacts when generated in c

Time:10-06

I've written myself a little C program to write a bitmap file from scratch. It works partially and I can't seem to find out why it doesn't work in certain cases. What works:

  • Setting a constant color
  • Setting a variable color using the loop index WHEN AT THE SAME TIME specifying an offset larger than 10.

What does not work:

  • Setting a variable color without offset or an offset smaller or equal to 10

What's (probably) not the problem:

  • image size is 1024 x 1024 -> no padding bytes required !
  • The bitmap file is recognized by the windows "photo viewer". I also tried paint and gimp: the format is recognised and I get the same images.

For the whole code see below, here are the parts I deem important:

#pragma pack(push, 1) // no padding !
struct bmpHeader {
    uint16_t hdrField; // set to 'B' 'M'
    uint32_t fileSize;
    uint16_t res1;
    uint16_t res2;
    uint32_t imgDataOffset;
};

struct bmpCoreHeader {
    uint32_t hdrSize;
    uint16_t width;
    uint16_t height;
    uint16_t colorPlanes; // 1
    uint16_t bitsPerPixel; // 24
};

struct pixel {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
};

And the loop used for filling:

for (uint32_t i = 0; i < cHdr.width; i  )
    {
        for (uint32_t j = 0; j < cHdr.height; j  )
        {
            imageData->at(i).at(j).blue = 0;//j % 256;
            imageData->at(i).at(j).red = i % 128   0;
            imageData->at(i).at(j).green = 0;
        }
        //std::cout << i << ": ";
        //std::cout <<  imageData->at(i).at(0).blue << std::endl;
    }

I expect the above loop to produce an image that creates black-to-red fades. What it actually creates: Produced bitmap (cropped image to half height, full width)

You can find the following artifacts on the boundary between the colors: enter image description here

HOWEVER, when I set an offset like the following: imageData->at(i).at(j).red = i % 128 11; I get: Produced bitmap with offset 11 Any offset below 11 produces the same faulty picture. I have no idea of what's going on here.

Here is the full code:

#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdint>
#include <array>

constexpr uint16_t width = 1024;
constexpr uint16_t height = 1024;

#pragma pack(push, 1)
struct bmpHeader {
    uint16_t hdrField;
    uint32_t fileSize;
    uint16_t res1;
    uint16_t res2;
    uint32_t imgDataOffset;
};

struct bmpCoreHeader {
    uint32_t hdrSize;
    uint16_t width;
    uint16_t height;
    uint16_t colorPlanes;
    uint16_t bitsPerPixel;
};

struct pixel {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
    //uint8_t padding;
};

#pragma pack(pop)

int main()
{
    bmpHeader hdr;
    hdr.hdrField = 0x4d42;
    // size is set at the end
    hdr.fileSize = 0;
    hdr.res1 = 0;
    hdr.res2 = 0;
    hdr.imgDataOffset = sizeof(bmpHeader)   sizeof(bmpCoreHeader);

    bmpCoreHeader cHdr = { 0 };
    cHdr.hdrSize = sizeof(cHdr);
    cHdr.width = width;
    cHdr.height = height;
    cHdr.colorPlanes = 1;
    cHdr.bitsPerPixel = 24;

    std::array<std::array<pixel, width>, height>* imageData = new std::array<std::array<pixel, width>, height>;

    hdr.fileSize = sizeof(bmpHeader)   sizeof(bmpCoreHeader)   sizeof(*imageData);

    for (uint32_t i = 0; i < cHdr.width; i  )
    {
        for (uint32_t j = 0; j < cHdr.height; j  )
        {
            imageData->at(i).at(j).blue = 0;//j % 256;
            imageData->at(i).at(j).red = i % 128   9;
            imageData->at(i).at(j).green = 0;
        }
        //std::cout << i << ": ";
        //std::cout <<  imageData->at(i).at(0).blue << std::endl;
    }

    char* bmpContent = new char[sizeof(bmpHeader)   sizeof(bmpCoreHeader)   sizeof(*imageData)];
    std::cout << "Image data size: " << sizeof(*imageData) << std::endl;

    memcpy(bmpContent, &hdr, sizeof(bmpHeader));
    memcpy(bmpContent   sizeof(bmpHeader), &cHdr, sizeof(bmpCoreHeader));
    memcpy(bmpContent   sizeof(bmpHeader)   sizeof(bmpCoreHeader), imageData, sizeof(*imageData));
    
    std::fstream bmpFile("image.bmp", std::fstream::out);
    if (!bmpFile.is_open())
    {
        std::cout << "Could not open / create BMP file" << std::endl;
        return 1;
    }
    bmpFile.write(bmpContent, hdr.fileSize);

    return 0;
}

Any input is greatly appreciated =)

CodePudding user response:

The file needs to be opened as binary, otherwise any 0A is replaced with 0D0A which will mess up alignment

    std::ofstream bmpFile("image.bmp", std::ios_base::binary);

(ref https://docs.microsoft.com/en-us/cpp/standard-library/binary-output-files)

  • Related