在 C++ 中生成时的位图工件

bitmap artifacts when generated in c++

我自己编写了一个小的 C++ 程序来从头开始编写位图文件。它部分起作用,我似乎无法找出为什么它在某些情况下不起作用。 什么有效:

什么不起作用:

什么(可能)不是问题:

完整代码见下文,以下是我认为重要的部分:

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

以及用于填充的循环:

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

我希望上面的循环生成一个图像,该图像会创建从黑到红的淡入淡出。它实际上创造了什么: (将图像裁剪为半高、全宽)

您可以在颜色之间的边界上找到以下伪像:

但是,当我设置如下偏移量时: imageData->at(i).at(j).red = i % 128 + 11; 我得到: 任何低于 11 的偏移都会产生相同的错误图片。我不知道这里发生了什么。

完整代码如下:

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

非常感谢任何输入=)

文件需要以二进制方式打开,否则 0A 会被 0D0A 替换,这会导致对齐混乱

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

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