2014-07-23 1 views
1

J'ai donc un problème pour trouver exactement ce qui ne va pas en essayant de lire une image bitmap 24bpp et de la recréer dans le même dossier. Cela fonctionne avec une image, mais pas deux autres avec lesquelles je l'ai testé. En lisant depuis le bitmap, j'utilise les informations trouvées dans l'en-tête lui-même. On pourrait dire que j'ai trois questions. 1) Est-ce que je lis correctement à partir d'un bitmap? 2) Est-ce que je calcule/utilise/écrit correctement le rembourrage? 3) Suis-je en train de sortir correctement? Troisième est confirmé non avec cette image et sa sortie.Copie/Sortie Bitmap incorrecte

La raison de l'allocation d'un tableau 2d pour les images est aussi que je peux essayer de faire pivoter les images bitmap de 90 degrés.

Malheureusement, je ne peux pas poster des images, l'image prise est d'ici, le rgb_24bpp.bmp http://pyglet.googlecode.com/svn/trunk/tests/image/

Voici le code utilisé pour la lecture de l'image et de calculer le rembourrage. Begin/end/test sont tous des streampos et sont imprimés sur la console pour le débogage.

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(); 

Et c'est le code utilisé pour sortir/recréer l'image.

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(); 

J'ai confirmé que les deux en-têtes sont corrects et peuvent en tirer des données correctement dans trois tests différents. En utilisant ce code gars (désolé, ce projet est non commercial et auto-étude seulement). À l'exception de commenter le réservé dans le RGBQUAD et de faire efficacement un RGBTRI à la place.

+0

Y a-t-il une raison pour laquelle vous avez alloué de l'espace sur le tas individuellement pour chaque pixel? – Logicrat

+0

Je le fais de cette façon pour plus de simplicité/compréhension, après avoir regardé ici http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new je me rends compte C'est lourd et inefficace, mais cela simplifie l'utilisation du tableau 2d pour moi-même. – Draxe

+0

J'ai travaillé avec des fichiers BMP en faisant quelques fichiers de test en utilisant des outils tels que MS PAINT, et en créant des fichiers solides blancs ou noirs avec un seul pixel de couleur différente dans chaque coin. Cela facilite le passage à travers votre code avec un débogueur et assurez-vous que l'alignement des lignes est correct. L'alignement des lignes a été la source de la plupart de mes problèmes lorsque je travaillais avec BMP. – Logicrat

Répondre

0

Vous pouvez le faire comme ça .. Aussi, si vous ne voulez pas faire un tableau temporaire pour copier les pixels, vous pouvez facilement lire, chercher, lire, chercher, etc. OU vous pouvez simplement lire tout immediatement. Il y a tellement de façons de lire un bitmap et d'être efficace/inefficace. C'est à vous de voir comment vous voulez le faire. Une autre façon efficace de le faire est de sauvegarder le BitmapInfoHeader et BitmapFileHeader. Ensuite, lorsque vous décidez d'écrire le bitmap sur le disque, écrivez simplement les en-têtes en premier puis les pixels. WAY plus rapide et plus facile .. Je n'ai pas fait cela dans cet exemple. Je vais vous laisser le soin de comprendre.

Voici un exemple de code que j'ai écrit pour répondre à votre question. Je préfère utiliser des tableaux à une dimension.

#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); 
}