我有一个项目,涉及将.bmp文件读入C程序,在其上放置一个掩码,然后将带有掩码的版本打印回另一个文件。我遇到问题的部分似乎是在文件中读取的实际过程。我看到的第一个大红旗是它继续以错误的分辨率阅读。我已经搜索了很多,看到一些脚本在.bmp文件中读取作为各种问题的答案,但使用这些脚本中的逻辑并没有帮助。
主要问题似乎是,不是在我教授给出的示例图像中读取200 x 300的正确尺寸,而是读入13107200 x 65536.但是,如果我要包含代码的一部分,打印到不同的文件,您会看到输出文件具有适当的分辨率。这告诉我,我可能正确地阅读了信息,但没有以我认为的方式存储它。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct HEADER {
unsigned short int Type; // Magic indentifier
unsigned int Size; // File size in bytes
unsigned short int Reserved1, Reserved2;
unsigned int Offset; // Offset to data (in B)
} Header; // -- 14 Bytes
struct INFOHEADER {
unsigned int Size; // Header size in bytes
int Width, Height; // Width / height of image
unsigned short int Planes; // Number of colour planes
unsigned short int Bits; // Bits per pixel
unsigned int Compression; // Compression type
unsigned int ImageSize; // Image size in bytes
int xResolution, yResolution; // Pixels per meter
unsigned int Colors; // Number of colors
unsigned int ImportantColors; // Important colors
} InfoHeader; // -- 40 Bytes
struct PIXEL {
unsigned char Red, Green, Blue; // Intensity of Red, Green, and Blue
}; // -- 3 Bytes
int getFileSize(FILE *input);
int getHexVal(FILE *input);
struct HEADER *getHeader(FILE *input);
struct INFOHEADER *getInfoHeader(FILE *input);
struct PIXEL *getPixel(FILE *input, struct PIXEL *loc);
struct HEADER *printHeader(FILE *output);
struct INFOHEADER *printInfoHeader(FILE *output);
struct PIXEL *printPixel(FILE *output, struct PIXEL *loc);
int main(int argc, char const *argv[]) {
if (argc == 3) {
if (!strcmp(argv[1], argv[2])) {
printf("The input and output file must be different. Please try again.\n");
return 1;
}
// char Matrix[3][3] =
// { { 0, -1, 0 },
// { -1, 4, -1 },
// { 0, -1, 0 }
// };
FILE *input = fopen(argv[1], "rb");
if (!input) return 1;
int i, j;
// getHeader(input);
fread(&Header, sizeof(struct HEADER), 1, input);
if (Header.Type != 0x4D42) {
printf("The specified input file was not a bitmap. Please try again.");
fclose(input);
return 1;
}
// getInfoHeader(input);
fread(&InfoHeader, sizeof(struct INFOHEADER), 1, input);
fseek(input, Header.Offset, SEEK_SET);
struct PIXEL arr[InfoHeader.Width][InfoHeader.Height];
printf("%d %d\n", InfoHeader.Width, InfoHeader.Height);
for (i = 0; i < InfoHeader.Width; i++) {
for (j = 0; j < InfoHeader.Height; j++) {
getPixel(input, arr[i] + j);
printf("%d %d %d\n", arr[i][j].Red, arr[i][j].Green, arr[i][j].Blue);
}
}
fclose(input);
}
}
答案 0 :(得分:6)
我可以看到您的代码存在很多问题:
<强> 1。数据类型的大小不一致
在不同的平台上,int
和short
等类型可以有不同的大小。因此,int
可能在一个平台上是一个大小,在另一个平台上可能是另一个大小。您可能需要使用精确大小的类型,例如uint32_t
。
<强> 2。填充和对齐
存储在文件中的标题已打包。你的结构是对齐的。这意味着编译器在成员之间插入填充以确保成员始终对齐以获得最佳内存访问。
有多种方法可以解决这个问题。您可以声明要打包的结构。这会让你到目前为止,但看到下一点。
第3。字节序强>
如果您正在大端系统上读取Windows位图,则可以将文件中的小端数据转换为系统的大端数据。
<强> 4。 xResolution,yResolution是错误的成员
这些用于表示像素的物理尺寸。在实践中,它们很少被指定。您打算阅读Width
和Height
。
<强> 5。 VLA(gah!)
您正在使用可变长度数组:struct PIXEL arr[InfoHeader.xResolution][InfoHeader.yResolution]
。这很容易导致大位图的堆栈溢出。您确实需要为像素阵列使用动态分配的内存。
我如何处理这些问题?
malloc
答案 1 :(得分:5)
类型int
和short
等仅保证具有特定的最小尺寸。它们可以根据不同的实现而变化即使我们假设int
和short
分别是四个和两个八位字节,在阅读和编写结构时仍然会遇到问题。
例如:
struct HEADER {
unsigned short int Type;
unsigned int Size;
unsigned short int Reserved1, Reserved2;
unsigned int Offset;
} Header;
为了使Size
与处理器适当对齐,编译器将(通常)在Type
和Size
之间插入填充,将Size
置于偏移+4处为+2(假设上述尺寸)。
读取(和写入)二进制格式的最佳方法是将文件读入unsigned char *
缓冲区,然后从那里提取字段。例如
unsigned long Size = buffer[2] +
buffer[3] * 0x100UL +
buffer[4] * 0x10000UL +
buffer[5] * 0x1000000UL;
或类似。
答案 2 :(得分:0)
我怀疑你混淆了一些领域。 看了http://en.wikipedia.org/wiki/BMP_file_format之后,我想而不是这个
struct PIXEL arr[InfoHeader.xResolution][InfoHeader.yResolution];
你真的是这个意思:
struct PIXEL arr[InfoHeader.Width][InfoHeader.Height];