C++:在 WINDOWS 上写入 BMP 图像格式错误
C++: Write BMP image format error on WINDOWS
我在这里遇到最奇怪的问题...我使用的是从 Linux 到 Windows 到 READ[=33= 的相同代码(复制粘贴) ] 和 WRITE 和 BMP 图片。由于某些原因,在 Linux 中,一切正常 非常好 ,但是当我来到 Windows 10 来自一些我无法打开该图像,并且我收到一条错误消息是怎么说的:
"It looks like we don't support this file format."
你知道我该怎么做吗?我会把代码放在下面。
编辑:
我已经解决了填充问题,现在它正在写入图像,但它们完全是 白色,知道为什么吗?我也更新了代码。
struct BMP {
int width;
int height;
unsigned char header[54];
unsigned char *pixels;
int size;
int row_padded;
};
void writeBMP(string filename, BMP image) {
string fileName = "Output Files\" + filename;
FILE *out = fopen(fileName.c_str(), "wb");
fwrite(image.header, sizeof(unsigned char), 54, out);
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
fwrite(image.pixels, sizeof(unsigned char), image.row_padded, out);
}
fclose(out);
}
BMP readBMP(string filename) {
BMP image;
string fileName = "Input Files\" + filename;
FILE *f = fopen(fileName.c_str(), "rb");
if (f == NULL)
throw "Argument Exception";
fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
image.width = *(int *) &image.header[18];
image.height = *(int *) &image.header[22];
image.row_padded = (image.width * 3 + 3) & (~3);
image.pixels = new unsigned char[image.row_padded];
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
fread(image.pixels, sizeof(unsigned char), image.row_padded, f);
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
}
fclose(f);
return image;
}
在我看来这段代码应该是跨平台的...但它不是...为什么?
感谢帮助
勾选header
header must start with the following two signature 个字节:0x42 0x4D
。如果它有所不同,第三方应用程序会认为此文件不包含 bmp 图片,尽管文件扩展名为 .bmp。
像素的大小和存储方式也有点more complex than what you expect:你假设每个像素的位数是24,不使用压缩。这是无法保证的。如果不是这种情况,您可能会读取比可用数据更多的数据,并在写回文件时损坏文件。
此外,header 的大小还取决于 BMP version you are using, which you can detect using 偏移量 14 处的 4 字节整数。
改进您的代码
加载文件时,检查签名、bmp 版本、每像素位数和压缩。出于调试目的,考虑转储 header 以手动检查它:
for (int i=0; i<54; i++)
cout << hex << image.header[i] << " ";`
cout <<endl;
此外,当您 fread()
检查读取的字节数是否与您想要读取的大小相对应时,请确保您没有使用未初始化的缓冲区数据。
编辑:
检查转储后,格式似乎符合预期。但是用你计算的填充大小验证 header 中的填充大小,错误就在这里:
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.pixels = new unsigned char[image.row_padded]; // oops ! A little short ?
其实你是一行一行看的,但是你只记住了最后一个!这与您的第一个版本不同,您在第一个版本中确实读取了图片的完整像素。
同理,你写最后一行重复高度的时间。
重新考虑您的填充,使用总填充大小。
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.size_padded = image.row_padded * image.height; // padded full size
image.pixels = new unsigned char[image.size_padded]; // yeah !
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, f) != image.size_padded) {
cout << "Error: all bytes couldn't be read"<<endl;
}
else {
... // process the pixels as expected
}
...
我在这里遇到最奇怪的问题...我使用的是从 Linux 到 Windows 到 READ[=33= 的相同代码(复制粘贴) ] 和 WRITE 和 BMP 图片。由于某些原因,在 Linux 中,一切正常 非常好 ,但是当我来到 Windows 10 来自一些我无法打开该图像,并且我收到一条错误消息是怎么说的:
"It looks like we don't support this file format."
你知道我该怎么做吗?我会把代码放在下面。
编辑:
我已经解决了填充问题,现在它正在写入图像,但它们完全是 白色,知道为什么吗?我也更新了代码。
struct BMP {
int width;
int height;
unsigned char header[54];
unsigned char *pixels;
int size;
int row_padded;
};
void writeBMP(string filename, BMP image) {
string fileName = "Output Files\" + filename;
FILE *out = fopen(fileName.c_str(), "wb");
fwrite(image.header, sizeof(unsigned char), 54, out);
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
fwrite(image.pixels, sizeof(unsigned char), image.row_padded, out);
}
fclose(out);
}
BMP readBMP(string filename) {
BMP image;
string fileName = "Input Files\" + filename;
FILE *f = fopen(fileName.c_str(), "rb");
if (f == NULL)
throw "Argument Exception";
fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
image.width = *(int *) &image.header[18];
image.height = *(int *) &image.header[22];
image.row_padded = (image.width * 3 + 3) & (~3);
image.pixels = new unsigned char[image.row_padded];
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
fread(image.pixels, sizeof(unsigned char), image.row_padded, f);
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
}
fclose(f);
return image;
}
在我看来这段代码应该是跨平台的...但它不是...为什么?
感谢帮助
勾选header
header must start with the following two signature 个字节:0x42 0x4D
。如果它有所不同,第三方应用程序会认为此文件不包含 bmp 图片,尽管文件扩展名为 .bmp。
像素的大小和存储方式也有点more complex than what you expect:你假设每个像素的位数是24,不使用压缩。这是无法保证的。如果不是这种情况,您可能会读取比可用数据更多的数据,并在写回文件时损坏文件。
此外,header 的大小还取决于 BMP version you are using, which you can detect using 偏移量 14 处的 4 字节整数。
改进您的代码
加载文件时,检查签名、bmp 版本、每像素位数和压缩。出于调试目的,考虑转储 header 以手动检查它:
for (int i=0; i<54; i++)
cout << hex << image.header[i] << " ";`
cout <<endl;
此外,当您 fread()
检查读取的字节数是否与您想要读取的大小相对应时,请确保您没有使用未初始化的缓冲区数据。
编辑:
检查转储后,格式似乎符合预期。但是用你计算的填充大小验证 header 中的填充大小,错误就在这里:
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.pixels = new unsigned char[image.row_padded]; // oops ! A little short ?
其实你是一行一行看的,但是你只记住了最后一个!这与您的第一个版本不同,您在第一个版本中确实读取了图片的完整像素。
同理,你写最后一行重复高度的时间。
重新考虑您的填充,使用总填充大小。
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.size_padded = image.row_padded * image.height; // padded full size
image.pixels = new unsigned char[image.size_padded]; // yeah !
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, f) != image.size_padded) {
cout << "Error: all bytes couldn't be read"<<endl;
}
else {
... // process the pixels as expected
}
...