2012-07-30 92 views
6
#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 

int main() 
{ 
    FILE* bmp = NULL; 
    uint32_t offset; 
    uint8_t* temp = NULL; 
    size_t read; 
    unsigned int x_dim = 600, y_dim = 388; 

    bmp = fopen("test_colour.bmp", "r"); 

    if (!bmp) 
     return -1; 

    /* Get the image data offset */ 
    fseek(bmp, 10, SEEK_SET); 
    fgets((char*)&offset, 4, bmp); 

    printf("Offset = %u\n", offset); 

    temp = malloc(3*x_dim*y_dim*sizeof(uint8_t)); 

    if (!temp) 
     return -1; 

    /* Go the the position where the image data is stored */ 
    fseek(bmp, offset, SEEK_SET); 

    /* Copy image data to array */ 
    printf("%u bytes requested!\n", 3*x_dim*y_dim); 
    read = fread((void*)temp, sizeof(uint8_t), 3*x_dim*y_dim, bmp); 
    printf("%Iu bytes read!\n", read); 

    fclose(bmp); 
    free(temp); 

    return 0; 
} 

我正在使用上面的代碼來讀取一個24位像素BMP圖像的RGB數據到一個數組。根據BMP規範,在偏移量10處給出從圖像數據開始處(在BMP標題之後)開始的文件的偏移量。執行上述代碼時,我會得到以下輸出。fread意外的返回值()

Offset = 54 
698400 bytes requested! 
33018 bytes read! 

由於文件大小爲698454字節(= 698400 + 54),偏移量輸出似乎是正確的。但是,fread()返回的值似乎表示不能讀取整個圖像數據。但是,隨後我使用temp陣列中的數據將RGB數據轉換爲灰度並將此數據再次寫入BMP文件。目測檢查輸出圖像並不表示任何錯誤,即似乎我實際上首先讀取了整個輸入圖像,儘管fread()似乎表示不同。

有人可以解釋這種行爲嗎?

+0

有兩個問題:1)你可以在調用'fread'之後檢查'temp'的內容,看它是否在33018字節後實際停止讀取? 2)我不熟悉'%Iu'格式說明符 - 你能在調試器中檢查'read'的實際值嗎? – Treb 2012-07-30 07:52:54

+0

我不認爲這是什麼導致你看到的症狀,但你應該使用正確的'printf'格式字符串。 'size_t'的格式是'「%zu」'。 '「%Iu」'是非標準的。如果你的實現不支持'「%zu」',你可以使用'printf(「%lu read read!\ n」,(unsigned long)read);' – 2012-07-30 07:55:23

+0

我使用gcc和MinGW進行編譯,編譯器無法識別'%zu'說明符(我曾嘗試使用該說明符)。我讀過,必須在窗口中使用'%Iu'。 – simon 2012-07-30 08:04:47

回答

20

(我敢打賭,你使用的是Windows)

bmp = fopen("test_colour.bmp", "r"); 

應該

bmp = fopen("test_colour.bmp", "rb"); 

如果該文件在Windows上以文本模式,運行時就會停止閱讀,當它發生命中一個0x1a(Ctrl-Z)字節,Windows將這個字節視爲文本文件的EOF標記。即使它沒有按Ctrl-Z,當Windows將CR/LF序列轉換爲單個LF字符時,也會損壞數據。

但是,我無法解釋爲什麼你能從部分文件讀取中獲得好的圖像(只是幸運?)。

由於fread()實現將緩衝區中所請求的字節數(或幾乎等於某個塊大小的整數)讀入緩衝區,因此您可以從緩衝區渲染圖像,然後它掃描尋找CR/LF序列的緩衝區以轉換和Ctrl-Z EOF標誌。

因此,即使fread()返回33018,緩衝區實際上幾乎完全用文件中的數據寫入。數據不是100%正確的(例如,某些CR字符可能被丟棄)或完整,但在這種情況下,它足夠接近以呈現看起來像您所期望的圖像。

當然,這只是觀察當前特定運行時的行爲 - 在將來(甚至在今天的所有系統中)可能並不總是這樣。

+0

事實上,我忘了在OP中提到。感謝您指出,解決了問題!你確定它確實停止閱讀嗎?如前所述,我仍然能夠發出整個BMP圖像的正確灰度圖像,但根據「fread」只有大約5%的文件數據被實際讀取。 – simon 2012-07-30 07:58:18

+0

@simon:運行時可能會將您請求的字節數讀入緩衝區,然後檢查它並「修復」行結束符和EOF轉換。但我只是猜測。 – 2012-07-30 08:15:49

+0

我比較了生成的兩個輸出圖像(一個用'「r」打開文件,另一個用'「rb」')用diff打開,它們不一樣。從視覺上看圖像,唯一的區別似乎是''r「'圖像中的最後幾個像素是黑色的,而實際上它們應該是白色的。所以我猜'fread'實際上讀取比返回值指示的更多的字節,但不一定是實際請求的字節數。 – simon 2012-07-30 08:27:57