2016-11-17 66 views
0

我最奇怪的問題在這裏...我使用相同的代碼(複製粘貼)在Linux在Windows READWRITEBMP圖片。並從某些原因,Linux的每一件事情的作品完全正常,但是當我來的Windows 10一些我無法打開圖片,我已經收到錯誤消息是怎麼說的是這樣的:C++:寫BMP圖像格式錯誤的WINDOWS

「看起來我們不支持這種文件格式。」

你知道該怎麼辦?我將把代碼放在下面。

編輯:

我已經解決了這個問題,填充現在是寫圖像,但它們是完全白色,任何想法,爲什麼?我也更新了代碼。

struct BMP { 
    int width; 
    int height; 
    unsigned char header[54]; 
    unsigned char *pixels; 
    int size; 
    int row_padded; 
}; 

void writeBMP(string filename, BMP image) { 
    string fileName = "Output Files\\" + filename; 
    FILE *out = fopen(fileName.c_str(), "wb"); 
    fwrite(image.header, sizeof(unsigned char), 54, out); 

    unsigned char tmp; 
    for (int i = 0; i < image.height; i++) { 
     for (int j = 0; j < image.width * 3; j += 3) { 
      // Convert (B, G, R) to (R, G, B) 
      tmp = image.pixels[j]; 
      image.pixels[j] = image.pixels[j + 2]; 
      image.pixels[j + 2] = tmp; 
     } 
     fwrite(image.pixels, sizeof(unsigned char), image.row_padded, out); 
    } 
    fclose(out); 
} 

BMP readBMP(string filename) { 
    BMP image; 
    string fileName = "Input Files\\" + filename; 
    FILE *f = fopen(fileName.c_str(), "rb"); 

    if (f == NULL) 
     throw "Argument Exception"; 

    fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header 

    // extract image height and width from header 
    image.width = *(int *) &image.header[18]; 
    image.height = *(int *) &image.header[22]; 

    image.row_padded = (image.width * 3 + 3) & (~3); 
    image.pixels = new unsigned char[image.row_padded]; 
    unsigned char tmp; 

    for (int i = 0; i < image.height; i++) { 
     fread(image.pixels, sizeof(unsigned char), image.row_padded, f); 
     for (int j = 0; j < image.width * 3; j += 3) { 
      // Convert (B, G, R) to (R, G, B) 
      tmp = image.pixels[j]; 
      image.pixels[j] = image.pixels[j + 2]; 
      image.pixels[j + 2] = tmp; 
     } 
    } 
    fclose(f); 
    return image; 

} 

在我看來,這個代碼應該是跨平臺的......但它不是......爲什麼?

感謝您的幫助

+0

您可以在窗口中使用比較工具,比如使用Visual Studio自帶的windiff來比較兩個文件。或者使用調試器確保寫入相同的圖像標題數據。 –

+0

比較什麼?這是完全一樣的代碼... – Mircea

+0

我已經檢查了這段代碼幾次,它是完全一樣的... – Mircea

回答

1

檢查頭

header必須具有以下兩個signature字節開始:0x42 0x4D。如果不同,第三方應用程序會認爲該文件不包含bmp圖片,儘管.bmp文件擴展名。

像素存儲的大小和方式也有點more complex than what you expect:您認爲每像素的位數是24,並且不使用不壓縮。這不能保證。如果不是這種情況,您可能會讀取比可用數據更多的數據,並在寫回文件時損壞文件。

此外,報頭的大小還取決於正在使用的BMP version,其you can detect using 4字節整數偏移量14.

提高代碼

當加載文件,檢查簽名,bmp版本,每個像素的位數和壓縮。爲了調試的目的,考慮傾銷頭手動檢查:

for (int i=0; i<54; i++) 
    cout << hex << image.header[i] << " ";` 
cout <<endl; 

此外,當你fread()檢查的字節數讀取對應於你想讀的大小,所以可以肯定你不是使用未初始化的緩衝區數據。

編輯:

檢查過場,看來該格式符合市場預期。但在加襯大小頭驗證填充的大小,你已經計算出它出現的錯誤是在這裏:

image.row_padded = (image.width * 3 + 3) & (~3);  // ok size of a single row rounded up to multiple of 4 
image.pixels = new unsigned char[image.row_padded]; // oops ! A little short ? 

事實上,你按行逐行讀取,但只保存在內存中的最後一個!這與你的第一個版本不同,你讀過圖片的全部像素。

同樣,你寫最後一行重複的高度時間。

重新考慮您的填充,使用總填充大小。

image.row_padded = (image.width * 3 + 3) & (~3);  // ok size of a single row rounded up to multiple of 4 
image.size_padded = image.row_padded * image.height; // padded full size 
image.pixels = new unsigned char[image.size_padded]; // yeah ! 
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, f) != image.size_padded) { 
    cout << "Error: all bytes couldn't be read"<<endl; 
} 
else { 
    ... // process the pixels as expected 
} 
... 
+0

我已經解決了我的問題的一部分,我編輯了我的問題,可以再檢查一次嗎? – Mircea

+0

@Mircea我編輯了我的答案 – Christophe

+0

好吧...輸入圖像沒問題,我可以打開它並觀察它。我的問題只是輸出圖像。我已經檢查了標題倍數倍,這是完美的,或者我看不出差異。我甚至用'for(int i = 0; i <54; i ++)來檢查cout << hex << image.header [i] <<「」;;'這是一樣的......現在如果我有權利,在這一刻我的問題不是標題,它是像素數組。出於某種原因,我已經以某種方式失去了所有像素......或者我沒有正確書寫它。我認爲這是我在這一刻的問題。 – Mircea