2012-11-13 107 views
2

我發現自己正在編寫一個簡單的程序來從bmp文件中提取數據。我剛剛開始,我正處於WTF時刻之一。c從BMP獲取數據

當我運行該程序,並提供該圖片:http://www.hack4fun.org/h4f/sites/default/files/bindump/lena.bmp

我得到的輸出:

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

實際的圖像大小爲786486個字節。爲什麼我的代碼報告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; 
} 
+0

請確保您的BMP_FILE_HEADER是打包的,即sizeof(BMP_FILE_HEADER)== 14 – Musa

+0

@Musa這是16.謝謝,現在我有一些事情要繼續。 –

回答

1

我可以在代碼中找到兩處錯誤。

第一個錯誤:您必須將結構打包爲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') 

您試圖檢查short類型,這是2個字節,用char型(使用''),這是1個字節。編譯器可能會給你一個警告,單引號只包含1個字節和1個字節大小的規範。

爲了解決這個問題,您可以將這2個字節分成2個已知的1字節字符(MB),並將它們放在一起爲word。例如:

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

如果你看到這個表情,會出現這種情況:

'M'(這是ASCII 0x4D)轉移8位到左側,將導致0x4D00,現在你可以右邊的下一個字符爲零:0x4D00 | 0x42 = 0x4D42(其中0x42'B'的ASCII碼)。像這樣思考,你可以寫:

if (file_header.type != 0x4D42) 

然後你的代碼應該工作。

2

這裏頭十六進制:

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`,這是英特爾順序;作爲32位值處理,它是0x000c0036或十進制786,486(與保存的文件大小相匹配)。

可能您的C編譯器將每個字段對齊到32位邊界。啓用包結構選項,雜注或指令。

+0

謝謝。像魅力一樣工作,在結構之前添加了'#pragma pack()'。 –