2014-07-23 89 views
1

所以我有一個問題搞清楚到底是什麼,試圖讀取任何支持24 bpp位圖圖像,並在同一文件夾重新創建它會錯。它適用於一個圖像,但不是我已經測試過的兩個圖像。當從位圖中讀取時,我使用標題本身中的信息。可以說我有三個問題。 1)我正確讀取位圖嗎? 2)我是否正確計算/使用/寫入填充? 3)我輸出是否正確? 三是確認否與此圖像及其輸出。不正確的位圖複製/輸出

同樣對於分配的2D陣列的圖像的原因是,這樣我嘗試後者可以通過旋轉90度位圖。

可惜我不能發表圖片,拍攝的圖像是從這裏開始,在rgb_24bpp.bmp http://pyglet.googlecode.com/svn/trunk/tests/image/

這是用於從圖像讀取計算填充用代碼。

ifstream myBitmap("rgb_24bpp.bmp", ios::binary | ios::beg); 

// Get the total file size in bytes, testing file access 
begin = myBitmap.tellg(); 
myBitmap.seekg(0, ios::end); 
end = myBitmap.tellg(); 

// Actually reading image file 
myBitmap.seekg(0, ios::beg); 
myBitmap.read((char*)FileHeader, sizeof(BITMAPFILEHEADER)); 
myBitmap.read((char*)InfoHeader, sizeof(BITMAPINFOHEADER)); 
test = myBitmap.tellg(); 

RGBQUAD ** Image = new RGBQUAD*[InfoHeader->biWidth]; 
for (int i = 0; i < InfoHeader->biWidth; ++i) { 
    Image[i] = new RGBQUAD[InfoHeader->biHeight]; 
} 
int pitch = InfoHeader->biWidth * 3; 

if (pitch % 4 != 0) 
{ 
    pitch += 4 - (pitch % 4); 
} 

int padding = pitch - (InfoHeader->biWidth * 3); 
cout << "padding: " << padding << endl; 

myBitmap.seekg(FileHeader->bfOffBits, ios::beg); 
for (int i = InfoHeader->biHeight; i > 0; --i) { 
    for (int j = 0; j < InfoHeader->biWidth; ++j) { 
     myBitmap.read((char*)&Image[j][i], sizeof(RGBQUAD)); 
    } 
    if (padding != 0) myBitmap.read(PadBuffer, padding); 
} 
myBitmap.close(); 

begin/end/test都是streampos並打印在控制檯上進行調試。 這是用於輸出/重新創建圖像的代碼。

ofstream BitmapOut("Output.bmp"); 
BitmapOut.write((char*)FileHeader, sizeof(BITMAPFILEHEADER)); 
BitmapOut.write((char*)InfoHeader, sizeof(BITMAPINFOHEADER)); 
for (int i = InfoHeader->biHeight; i > 0; --i) { 
    for (int j = 0; j < InfoHeader->biWidth; ++j) { 
     BitmapOut.write((char*)&Image[j][i], sizeof(RGBQUAD)); 
    } 
    if (padding != 0) BitmapOut.write("\0\0\0\0\0\0\0", padding); 
} 

BitmapOut.close(); 

我已經證實,這兩個標題是確實是正確的,可以從他們正常在3次不同的測試中提取數據。 利用這個傢伙代碼(對不起,這個項目只是非商業和自學)。 reading a .bmp file in c++

除了註釋掉RGBQUAD中保留的內容,並有效地改寫RGBTRI外。

+0

是否有某些原因讓您爲每個像素單獨分配堆空間? – Logicrat

+0

我做這種方式更多的簡單/理解,在這裏看我http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new後實現這是沉重而低效的,但它簡化了我自己使用2D陣列。 – Draxe

+0

我已讓使用工具,如MS PAINT一些測試文件,並在每個角落一個不同顏色的像素生成純白色或純黑色的文件與BMP文件的工作。這樣可以很容易地使用調試器來執行代碼,並確保您具有正確的行對齊方式。使用BMP時,行對齊一直是我的大多數問題的來源。 – Logicrat

回答

0

你能做到這樣的..另外,如果你不想做一個臨時數組複製的像素,可以輕鬆地閱讀,搜索,閱讀,搜索,等等。或者你可以閱讀所有立刻。讀取位圖有很多種方法,並且效率很高/效率低下。這取決於你如何去做。另一種有效的方法是保存BitmapInfoHeader和BitmapFileHeader。然後,當您決定將位圖寫入磁盤時,只需先將它們寫入標題,然後再寫入像素。方式更快,更容易..我沒有在這個例子中做到這一點。我會留給你弄清楚。

這裏是一個示例代碼,我寫了回答你的問題。我更喜歡使用1維數組。

#include <fstream> 
#include <cstring> 
#include <windows.h> 

typedef struct 
{ 
    unsigned int width, height; 
    unsigned char* pixels; 
} Bitmap; 

void InitBitmap(Bitmap* bmp) 
{ 
    if (bmp) 
    { 
     bmp->width = 0; 
     bmp->height = 0; 
     bmp->pixels = NULL; 
    } 
} 

void FreeBitmap(Bitmap* bmp) 
{ 
    if (bmp && bmp->pixels) 
    { 
     bmp->width = 0; 
     bmp->height = 0; 
     delete[] bmp->pixels; 
     bmp->pixels = NULL; 
    } 
} 

bool ReadBitmap(const char* FilePath, Bitmap* bmp) 
{ 
    std::fstream hFile(FilePath, std::ios::in | std::ios::binary); 

    if (!bmp || !hFile.is_open()) 
     return false; 

    BITMAPINFO Info; 
    BITMAPFILEHEADER Header; 
    memset(&Info, 0, sizeof(Info)); 
    memset(&Header, 0, sizeof(Header)); 

    hFile.read((char*)&Header, sizeof(Header)); 
    hFile.read((char*)&Info.bmiHeader, sizeof(Info.bmiHeader)); 

    bmp->width = Info.bmiHeader.biWidth; 
    bmp->height = Info.bmiHeader.biHeight < 0 ? -Info.bmiHeader.biHeight : Info.bmiHeader.biHeight; 
    size_t size = Info.bmiHeader.biSizeImage; 

    bmp->pixels = new unsigned char[size]; 
    hFile.seekg(Header.bfOffBits, std::ios::beg); 
    hFile.read((char*)bmp->pixels, size); 
    hFile.close(); 

    return true; 
} 

bool WriteBitmap(const char* FilePath, Bitmap* bmp) 
{ 
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary); 

    if (!bmp || !hFile) 
     return false; 

    BITMAPINFO Info; 
    BITMAPFILEHEADER Header; 
    memset(&Info, 0, sizeof(Info)); 
    memset(&Header, 0, sizeof(Header)); 

    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    Info.bmiHeader.biWidth = bmp->width; 
    Info.bmiHeader.biHeight = bmp->height; 
    Info.bmiHeader.biPlanes = 1; 
    Info.bmiHeader.biBitCount = 24; 
    Info.bmiHeader.biCompression = BI_RGB; 
    Info.bmiHeader.biSizeImage = 0; 
    Header.bfType = 0x4D42; 
    Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
    size_t size = (((24 * bmp->width + 31) & ~31)/8) * bmp->height; 

    hFile.write((char*)&Header, sizeof(Header)); 
    hFile.write((char*)&Info.bmiHeader, sizeof(Info.bmiHeader)); 
    hFile.write((char*)bmp->pixels, size); 
    hFile.close(); 
    return true; 
} 

int main() 
{ 
    Bitmap bmp; 
    InitBitmap(&bmp); 

    ReadBitmap("C:/Users/Brandon/Desktop/foo.bmp", &bmp); 
    WriteBitmap("C:/Users/Brandon/Desktop/foo2.bmp", &bmp); 

    FreeBitmap(&bmp); 
}