【问题标题】:c get data from BMPc 从 BMP 获取数据
【发布时间】:2012-11-13 10:54:34
【问题描述】:

我发现自己正在编写一个简单的程序来从 bmp 文件中提取数据。我刚刚开始,我正处于 WTF 时刻之一。

当我运行程序并提供此图像时:http://www.hack4fun.org/h4f/sites/default/files/bindump/lena.bmp

我得到了输出:

type: 19778
size: 12
res1: 0
res2: 54
offset: 2621440

实际图像大小为 786,486 字节。为什么我的代码报告 12 个字节?

中指定的标头格式, http://en.wikipedia.org/wiki/BMP_file_format 匹配我的 BMP_FILE_HEADER 结构。那么为什么它会充满错误的信息呢?

图像文件似乎没有损坏,并且其他图像给出同样错误的输出。我错过了什么?

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    unsigned short type;
    unsigned int size;
    unsigned short res1;
    unsigned short res2;
    unsigned int offset;
} BMP_FILE_HEADER;

int main (int args, char ** argv) {
    char *file_name = argv[1];

    FILE *fp = fopen(file_name, "rb");

    BMP_FILE_HEADER file_header;

    fread(&file_header, sizeof(BMP_FILE_HEADER), 1, fp);

    if (file_header.type != 'MB') {
        printf("ERROR: not a .bmp");
        return 1;
    }

    printf("type: %i\nsize: %i\nres1: %i\nres2: %i\noffset: %i\n", file_header.type, file_header.size, file_header.res1, file_header.res2, file_header.offset);
    fclose(fp);

    return 0;
}

【问题讨论】:

  • 确保您的BMP_FILE_HEADER 已打包,即 sizeof(BMP_FILE_HEADER) == 14
  • @Musa 现在是 16 岁。谢谢,现在我有事要做。

标签: c bmp


【解决方案1】:

这里是十六进制的标题:

0000000 42 4d 36 00 0c 00 00 00 00 00 36 00 00 00 28 00
0000020 00 00 00 02 00 00 00 02 00 00 01 00 18 00 00 00

长度字段为字节 36 00 0c 00`,按 intel 顺序排列;作为 32 位值处理,它是 0x000c0036 或十进制 786,486(与保存的文件大小匹配)。

可能您的 C 编译器正在将每个字段对齐到 32 位边界。启用包结构选项、编译指示或指令。

【讨论】:

  • 谢谢。工作就像一个魅力,只是在结构之前添加了#pragma pack()
【解决方案2】:

我可以在您的代码中找到两个错误。

第一个错误:您必须将结构打包为 1,因此每个类型的大小都是其应有的大小,因此编译器不会将其对齐,例如 4 字节对齐。所以在你的代码中,short,不是 2 个字节,而是 4 个字节。这样做的诀窍是使用编译器指令来打包最近的结构:

#pragma pack(1)

typedef struct {
    unsigned short type;
    unsigned int size;
    unsigned short res1;
    unsigned short res2;
    unsigned int offset;
} BMP_FILE_HEADER;

现在它应该正确对齐了。

另一个错误在这里:

if (file_header.type != 'MB')

您正在尝试使用 1 个字节的 char 类型(使用 '')检查 short 类型,这是 2 个字节。可能编译器会对此发出警告,单引号仅包含 1 个字符且大小为 1 字节是规范的。

要解决这个问题,您可以将这 2 个字节分成 2 个 1 字节字符,它们是已知的(MB),然后将它们组合成一个 word。例如:

if (file_header.type != (('M' << 8) | 'B'))

如果你看到这个表达式,就会发生这种情况:

'M'(在 ASCII 中是 0x4D)向左移动 8 位,将得到 0x4D00,现在您可以只添加右边零的下一个字符:0x4D00 | 0x42 = 0x4D42(其中0x42 是 ASCII 中的'B')。这样想,你可以写:

if (file_header.type != 0x4D42)

那么你的代码应该可以工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 2011-07-09
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多