C 误读.bmp 文件的分辨率

标签 c gcc bmp

我有一个项目涉及将 .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);
    }
}

最佳答案

我可以看到你的代码有很多问题:

<强>1。数据类型大小不一致

在不同的平台上,intshort 等类型可以有不同的大小。因此,int 在一个平台上可能是一种尺寸,在不同平台上可能是另一种尺寸。您可能需要使用精确大小的类型,例如 uint32_t

<强>2。填充和对齐

存储在文件中的 header 是打包的。您的结构已对齐。这意味着编译器在成员之间插入填充以确保成员始终对齐以获得最佳内存访问。

有多种方法可以解决这个问题。您可以声明要打包的结构。到此为止,请看下一点。

<强>3。字节顺序

如果您正在大端系统上读取 Windows 位图,则您已将文件中的小端数据转换为系统的大端数据。

<强>4。 xResolution、yResolution 是错误的成员

这些是为了指示像素的物理大小。在实践中,它们很少被指定。您打算阅读 WidthHeight

<强>5。 VLA(啊!)

您正在使用可变长度数组:struct PIXEL arr[InfoHeader.xResolution][InfoHeader.yResolution]。这很容易导致大位图的堆栈溢出。您确实需要为像素阵列使用动态分配的内存。


我将如何处理这些问题?

  • 使用精确大小的类型。
  • 声明打包结构。
  • 从文件中读取结构,然后根据需要进行字节序校正。
  • 使用malloc分配像素数组。

关于C 误读.bmp 文件的分辨率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22795605/

相关文章:

c++ - C(++) 结构力额外填充

c - 链接堆栈未链接?

c - 如何将三元运算符合并到优先级攀升算法中?

c - ANSI C 书籍链接列表章节中的错误编译示例

macos - "Illegal Instruction: 4"错误是什么?为什么 "-mmacosx-version-min=10.x"可以修复它?

c - 生产者-消费者堆栈行为而不是队列

c++ - 为什么数组的大小会根据其在源代码中的位置而不一致?

c - 读取bmp文件并将数据发送到数组

ios - 如何将 UIImage 转换为 BMP 并另存为数据(不是 JPG 或 PNG)

BMP 图像头 - biXPelsPerMeter