在 C++ 中生成时的位图工件
bitmap artifacts when generated in c++
我自己编写了一个小的 C++ 程序来从头开始编写位图文件。它部分起作用,我似乎无法找出为什么它在某些情况下不起作用。
什么有效:
- 设置固定颜色
- 在指定偏移量大于 10 的同时使用循环索引设置可变颜色。
什么不起作用:
- 设置无偏移或偏移小于或等于 10 的可变颜色
什么(可能)不是问题:
- 图像大小为 1024 x 1024 -> 不需要填充字节!
- 位图文件被windows“照片查看器”识别。我还尝试了 paint 和 gimp:格式被识别并且我得到了相同的图像。
完整代码见下文,以下是我认为重要的部分:
#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)
我自己编写了一个小的 C++ 程序来从头开始编写位图文件。它部分起作用,我似乎无法找出为什么它在某些情况下不起作用。 什么有效:
- 设置固定颜色
- 在指定偏移量大于 10 的同时使用循环索引设置可变颜色。
什么不起作用:
- 设置无偏移或偏移小于或等于 10 的可变颜色
什么(可能)不是问题:
- 图像大小为 1024 x 1024 -> 不需要填充字节!
- 位图文件被windows“照片查看器”识别。我还尝试了 paint 和 gimp:格式被识别并且我得到了相同的图像。
完整代码见下文,以下是我认为重要的部分:
#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;
我得到:
完整代码如下:
#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)